Index: resources/data/defaultpresets.xml
===================================================================
--- resources/data/defaultpresets.xml	(revision 19228)
+++ resources/data/defaultpresets.xml	(working copy)
@@ -1323,8 +1323,11 @@
             <space />
             <optional text="Cycleway Lane Attributes">
                 <combo key="cycleway:both:lane" text="Lane type (both)" values_context="cycleway" values="advisory,exclusive"/>
+                <check key="cycleway:both:buffer" text="Has buffer between automobiles and cycleway (both)" />
                 <combo key="cycleway:left:lane" text="Lane type (left)" values_context="cycleway" values="advisory,exclusive"/>
+                <check key="cycleway:left:buffer" text="Has buffer between automobiles and cycleway (left)" />
                 <combo key="cycleway:right:lane" text="Lane type (right)" values_context="cycleway" values="advisory,exclusive"/>
+                <check key="cycleway:right:buffer" text="Has buffer between automobiles and cycleway (right)" />
             </optional>
             <optional text="Edit Highway Attributes:">
                 <combo key="highway" text="Highway" values="motorway,motorway_link,trunk,trunk_link,primary,primary_link,secondary,secondary_link,tertiary,tertiary_link,unclassified,residential,living_street,service,bus_guideway,construction" values_context="Highway" values_sort="false" />
Index: resources/data/validator/combinations.mapcss
===================================================================
--- resources/data/validator/combinations.mapcss	(revision 19228)
+++ resources/data/validator/combinations.mapcss	(working copy)
@@ -779,11 +779,14 @@
   group: tr("suspicious tag combination");
 }
 
-/* #17967 */
-*[highway=cycleway][cycleway=track] {
+/* #17967, #23932 */
+*[highway=cycleway][/^cycleway(:.*)?$/] {
   throwWarning: tr("{0} together with {1}. Remove {1}.", "{0.tag}", "{1.tag}");
   group: tr("suspicious tag combination");
   fixRemove: "cycleway";
+  assertMatch: "way highway=cycleway cycleway=track";
+  assertMatch: "way highway=cycleway cycleway:buffer=yes";
+  assertNoMatch: "way highway=cycleway";
 }
 
 /* #17973, #18183, #18331, #20318 */
@@ -1065,3 +1068,79 @@
   throwWarning: tr("{0} is lower or equal to {1} on {2}", "{1.key}", "{2.key}", "{0.key}");
   group: tr("suspicious tag combination");
 }
+
+/* #23932 */
+way[cycleway:right][cycleway:right!=lane][/^cycleway(:right|:both|):buffer$/],
+way[cycleway:left][cycleway:left!=lane][/^cycleway(:left|:both|):buffer$/],
+way[cycleway:both][cycleway:both!=lane][/^cycleway(:right|:left|:both|):buffer$/],
+way[cycleway][cycleway!=lane][/^cycleway(:right|:left|:both|):buffer$/] {
+  throwWarning: tr("{0} together with {1}", "{1.tag}", "{2.tag}");
+  group: tr("suspicious tag combination");
+  assertMatch: "way cycleway:right=separate cycleway:right:buffer=yes";
+  assertMatch: "way cycleway:left=shared_lane cycleway:buffer=no";
+  assertMatch: "way cycleway:both=track cycleway:left:buffer=yes";
+  assertMatch: "way cycleway=shared_busway cycleway:buffer=no";
+  assertNoMatch: "way cycleway:right=lane cycleway:right:buffer=no";
+  assertNoMatch: "way cycleway:left=lane cycleway:left:buffer=yes";
+  assertNoMatch: "way cycleway:both=lane cycleway:both:buffer=no";
+  assertNoMatch: "way cycleway:both=lane cycleway:left:buffer=yes";
+  assertNoMatch: "way cycleway:both=lane cycleway:buffer=no";
+  assertNoMatch: "way cycleway=lane cycleway:buffer=yes";
+  assertNoMatch: "way cycleway=lane cycleway:right:buffer=no";
+  assertNoMatch: "way cycleway=lane cycleway:both:buffer=no";
+}
+
+way[cycleway:right=separate][/^cycleway(:right|:both):.*$/], 
+way[cycleway:left=separate][/^cycleway(:left|:both):.*$/], 
+way[cycleway:both=separate][/^cycleway(:right|:left|:both):.*$/], 
+way[cycleway=separate][/^cycleway(:right|:left|:both):.*$/] {
+  throwWarning: tr("{0} together with {1}. Remove {1}.", "{0.tag}", "{1.tag}");
+  group: tr("suspicious tag combination");
+  assertMatch: "way cycleway:right=separate cycleway:right:surface=asphalt";
+  assertMatch: "way cycleway:right=separate cycleway:both:buffer=yes";
+  assertMatch: "way cycleway:right=separate cycleway:surface=asphalt";
+  assertMatch: "way cycleway:right=separate cycleway:buffer=no";
+  assertMatch: "way cycleway:left=separate cycleway:left:surface=asphalt";
+  assertMatch: "way cycleway:left=separate cycleway:both:buffer=yes";
+  assertMatch: "way cycleway:left=separate cycleway:surface=asphalt";
+  assertMatch: "way cycleway:left=separate cycleway:buffer=no";
+  assertMatch: "way cycleway:both=separate cycleway:right:surface=asphalt";
+  assertMatch: "way cycleway:both=separate cycleway:left:surface=asphalt";
+  assertMatch: "way cycleway:both=separate cycleway:both:buffer=yes";
+  assertMatch: "way cycleway:both=separate cycleway:surface=asphalt";
+  assertMatch: "way cycleway:both=separate cycleway:buffer=no";
+  assertMatch: "way cycleway=separate cycleway:right:surface=asphalt";
+  assertMatch: "way cycleway=separate cycleway:left:surface=asphalt";
+  assertMatch: "way cycleway=separate cycleway:both:buffer=yes";
+  assertMatch: "way cycleway=separate cycleway:surface=asphalt";
+  assertMatch: "way cycleway=separate cycleway:buffer=no";
+  assertNoMatch: "way cycleway:right=separate cycleway:left:surface=asphalt";
+  assertNoMatch: "way cycleway:left=separate cycleway:right:buffer=yes";
+  assertNoMatch: "way cycleway:both=separate";
+  assertNoMatch: "way cycleway=separate";
+}
+
+way[cycleway:right:buffer][!cycleway:right][!cycleway:both][!cycleway],
+way[cycleway:left:buffer][!cycleway:left][!cycleway:both][!cycleway],
+way[cycleway:both:buffer][!cycleway:both][!cycleway][!cycleway:left],
+way[cycleway:both:buffer][!cycleway:both][!cycleway][!cycleway:right],
+way[cycleway:buffer][!cycleway][!cycleway:both][!cycleway:left],
+way[cycleway:buffer][!cycleway][!cycleway:both][!cycleway:right] {
+  throwWarning: tr("{0} without {1}", "{0.key}", "{1.key}");
+  group: tr("missing tag");
+  fixAdd: "{1.key}=lane";
+  assertMatch: "way cycleway:right:buffer=yes";
+  assertMatch: "way cycleway:left=lane cycleway:right:buffer=no";
+  assertMatch: "way cycleway:left:buffer=yes";
+  assertMatch: "way cycleway:right=lane cycleway:left:buffer=yes";
+  assertMatch: "way cycleway:both:buffer=yes";
+  assertMatch: "way cycleway:buffer=no";
+  assertMatch: "way cycleway:left=lane cycleway:both:buffer=yes";
+  assertMatch: "way cycleway:right=lane cycleway:buffer=no";
+  assertNoMatch: "way cycleway:right=lane cycleway:right:buffer=yes";
+  assertNoMatch: "way cycleway:left=lane cycleway:left:buffer=yes";
+  assertNoMatch: "way cycleway:both=lane cycleway:both:buffer=yes";
+  assertNoMatch: "way cycleway=lane cycleway:buffer=yes";
+  assertNoMatch: "way cycleway:left=lane cycleway:right=lane cycleway:both:buffer=yes";
+  assertNoMatch: "way cycleway:left=lane cycleway:right=lane cycleway:buffer=no";
+}
