You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2021/04/13 12:27:47 UTC

[isis] branch master updated: ISIS-2604: remove DeficiencyFacet

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new 7cf7a1f  ISIS-2604: remove DeficiencyFacet
7cf7a1f is described below

commit 7cf7a1f3dc4ec5b2d7017ba974e4305e6ae4edf5
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Apr 13 14:27:32 2021 +0200

    ISIS-2604: remove DeficiencyFacet
---
 .../MethodPrefixBasedFacetFactoryAbstract.java     |  12 +-
 .../facets/OrphanedSupportingMethodValidator.java  |  12 +-
 .../action/ActionAnnotationFacetFactory.java       |   2 -
 ...nChoicesForCollectionParameterFacetFactory.java | 151 +++++++++------------
 .../annotation/HomePageFacetAnnotationFactory.java |  30 ++--
 .../actions/layout/ActionLayoutFacetFactory.java   |   2 -
 .../facets/all/deficiencies/DeficiencyFacet.java   |  73 ----------
 .../annotation/SortedByFacetAnnotationFactory.java |  58 ++++----
 .../metamodel/facets/jaxb/JaxbFacetFactory.java    |  87 ++++++------
 .../ViewModelSemanticCheckingFacetFactory.java     |  18 +--
 .../BookmarkPolicyFacetFallbackFactory.java        |   8 +-
 .../DomainObjectAnnotationFacetFactory.java        |  22 +--
 .../DomainServiceFacetAnnotationFactory.java       |  16 +--
 .../mixin/MetaModelValidatorForMixinTypes.java     |  10 +-
 .../NavigableParentAnnotationFacetFactory.java     |  31 ++---
 .../ObjectSpecIdMalformedValidator.java            |  73 ++++------
 ...jectSpecIdFacetDerivedFromClassNameFactory.java |  54 +++-----
 .../recreatable/RecreatableObjectFacetFactory.java |  12 +-
 .../annotation/TitleAnnotationFacetFactory.java    |  12 +-
 .../core/metamodel/progmodel/ProgrammingModel.java |  52 ++++---
 .../dflt/ProgrammingModelFacetsJava8.java          |  55 +++++---
 .../title/TitlesAndTranslationsValidator.java      |  21 +--
 .../specloader/SpecificationLoaderDefault.java     |  15 +-
 .../specloader/validator/MetaModelValidator.java   |   8 --
 .../validator/MetaModelValidatorAbstract.java      |  22 ---
 ...ModelValidatorForAmbiguousMixinAnnotations.java |   3 +-
 ...etaModelValidatorForConflictingOptionality.java |   3 +-
 .../validator/MetaModelValidatorVisiting.java      | 107 ---------------
 ...idator.java => MetaModelVisitingValidator.java} |  23 ++--
 ...ava => MetaModelVisitingValidatorAbstract.java} |  35 +++--
 .../specloader/validator/ValidationFailure.java    |  38 ++++++
 .../SupportingMethodValidatorRefinerFactory.java   |  10 +-
 .../jdo/metamodel/JdoProgrammingModel.java         |  14 +-
 .../query/JdoQueryAnnotationFacetFactory.java      |   4 +-
 .../object/query/VisitorForClauseAbstract.java     |  27 ++--
 .../facets/object/query/VisitorForFromClause.java  |  15 +-
 .../object/query/VisitorForVariablesClause.java    |  10 +-
 .../version/JdoVersionAnnotationFacetFactory.java  |  50 +++----
 ...DerivedFromJdoColumnAnnotationFacetFactory.java | 105 +++++++-------
 ...ndatoryFromJdoColumnAnnotationFacetFactory.java | 129 ++++++++----------
 ...DerivedFromJdoColumnAnnotationFacetFactory.java |  77 ++++-------
 ...AnnotationFacetFactoryTest_refineMetaModel.java |  61 ++++++---
 42 files changed, 651 insertions(+), 916 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/MethodPrefixBasedFacetFactoryAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/MethodPrefixBasedFacetFactoryAbstract.java
index c964e4d..fe3482e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/MethodPrefixBasedFacetFactoryAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/MethodPrefixBasedFacetFactoryAbstract.java
@@ -23,11 +23,11 @@ import java.util.function.IntFunction;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.collections.ImmutableEnumSet;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
+import org.apache.isis.core.metamodel.specloader.validator.MetaModelVisitingValidatorAbstract;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 import lombok.Getter;
 import lombok.NonNull;
@@ -98,7 +98,7 @@ implements MethodPrefixBasedFacetFactory {
         
         val noParamsOnly = getConfiguration().getCore().getMetaModel().getValidator().isNoParamsOnly();
 
-        programmingModel.addValidatorSkipManagedBeans(new MetaModelValidatorVisiting.Visitor() {
+        programmingModel.addValidator(new MetaModelVisitingValidatorAbstract() {
 
             @Override
             public String toString() {
@@ -106,7 +106,7 @@ implements MethodPrefixBasedFacetFactory {
             }
 
             @Override
-            public boolean visit(ObjectSpecification objectSpec) {
+            public void validate(ObjectSpecification objectSpec) {
 
                 // as an optimization only checking declared members (skipping inherited ones)  
                 
@@ -135,7 +135,7 @@ implements MethodPrefixBasedFacetFactory {
                                     + "be an action, then rename and use @ActionLayout(named=\"...\") or ignore "
                                     + "completely using @Programmatic";
 
-                            DeficiencyFacet.appendTo(
+                            ValidationFailure.raise(
                                     objectSpec,
                                     String.format(
                                             messageFormat, 
@@ -147,8 +147,6 @@ implements MethodPrefixBasedFacetFactory {
                     }
                 });
 
-                return true;
-
             }
         });
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/OrphanedSupportingMethodValidator.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/OrphanedSupportingMethodValidator.java
index 07c1105..3d698f2 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/OrphanedSupportingMethodValidator.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/OrphanedSupportingMethodValidator.java
@@ -29,10 +29,10 @@ import org.apache.isis.commons.internal.collections._Sets;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.specimpl.ObjectSpecificationAbstract;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 import lombok.val;
 
@@ -61,15 +61,15 @@ implements MetaModelRefiner {
             return; // continue
         }
 
-        programmingModel.addValidatorSkipManagedBeans(spec -> {
+        programmingModel.addVisitingValidatorSkipManagedBeans(spec -> {
             
             if(!(spec instanceof ObjectSpecificationAbstract)) {
-                return true; // continue
+                return; // continue
             }
 
             val potentialOrphans = ((ObjectSpecificationAbstract) spec).getPotentialOrphans();
             if(potentialOrphans.isEmpty()) {
-                return true; // continue
+                return; // continue
             }
 
             // methods known to the meta-model
@@ -93,7 +93,7 @@ implements MetaModelRefiner {
                 val messageFormat = "%s#%s: is assumed to support "
                         + "a property, collection or action. Unmet constraint(s): %s";
                 
-                DeficiencyFacet.appendTo(
+                ValidationFailure.raiseFormatted(
                         spec,
                         String.format(
                                 messageFormat,
@@ -104,8 +104,6 @@ implements MetaModelRefiner {
             });
 
             potentialOrphans.clear(); // no longer needed  
-            
-            return true; // continue
         });
 
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
index 0e580ae..7c86e10 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
@@ -27,7 +27,6 @@ import org.apache.isis.applib.mixins.system.HasInteractionId;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Collections;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
-import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.actcoll.typeof.TypeOfFacet;
 import org.apache.isis.core.metamodel.facets.actions.action.associateWith.AssociatedWithFacetForActionAnnotation;
@@ -47,7 +46,6 @@ import org.apache.isis.core.metamodel.facets.members.layout.group.LayoutGroupFac
 import org.apache.isis.core.metamodel.facets.members.publish.command.CommandPublishingFacetForActionAnnotation;
 import org.apache.isis.core.metamodel.facets.members.publish.execution.ExecutionPublishingActionFacetForActionAnnotation;
 import org.apache.isis.core.metamodel.facets.object.domainobject.domainevents.ActionDomainEventDefaultFacetForDomainObjectAnnotation;
-import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorForAmbiguousMixinAnnotations;
 import org.apache.isis.core.metamodel.util.EventUtil;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionChoicesForCollectionParameterFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionChoicesForCollectionParameterFacetFactory.java
index 10ddf87..60a288c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionChoicesForCollectionParameterFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionChoicesForCollectionParameterFacetFactory.java
@@ -23,7 +23,6 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.actions.action.associateWith.AssociatedWithFacet;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.collparam.semantics.CollectionSemanticsFacet;
 import org.apache.isis.core.metamodel.facets.object.autocomplete.AutoCompleteFacet;
 import org.apache.isis.core.metamodel.facets.param.autocomplete.ActionParameterAutoCompleteFacet;
@@ -34,7 +33,7 @@ import org.apache.isis.core.metamodel.spec.feature.MixedIn;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
 import org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionMixedIn;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 import lombok.val;
 
@@ -63,102 +62,86 @@ implements MetaModelRefiner {
             return;
         }
 
-        val vistingValidator = new MetaModelValidatorVisiting.Visitor() {
-            
-            @Override
-            public boolean visit(final ObjectSpecification objectSpec) {
-                
-                validate(objectSpec);
-                return true;
-            }
-
-            private void validate(final ObjectSpecification objectSpec) {
-                
-                // as an optimization only checking declared members (skipping inherited ones)  
-                objectSpec.streamDeclaredActions(MixedIn.INCLUDED)
-                .forEach(objectAction->{
-                    if(objectAction instanceof ObjectActionMixedIn) {
-                        // we'll report only the mixin
-                        return;
-                    }
-
-                    int paramNum = 0;
-                    for (ObjectActionParameter parameter : objectAction.getParameters()) {
-                        if(parameter.getFeatureType() == FeatureType.ACTION_PARAMETER_COLLECTION) {
-                            validateActionParameter_whenCollection(
-                                    objectSpec, objectAction, parameter, paramNum);
-                        }
-                        paramNum++;
-                    }
-                });
-            }
-
-            private void validateActionParameter_whenCollection(
-                    final ObjectSpecification objectSpec,
-                    final ObjectAction objectAction,
-                    final ObjectActionParameter parameter,
-                    final int paramNum) {
-
-
-                val collectionSemanticsFacet = parameter.getFacet(CollectionSemanticsFacet.class);
-                if (collectionSemanticsFacet != null) {
-                    // Violation if there are action parameter types that are assignable
-                    // from java.util.Collection but are not of
-                    // exact type List, Set, SortedSet or Collection.
-                    if(!collectionSemanticsFacet.value().isSupportedInterfaceForActionParameters()) {
-                        
-                        val messageFormat = "Collection action parameter found that is not exactly one "
-                                + "of the following supported types: "
-                                + "List, Set, SortedSet, Collection or Array.  "
-                                + "Class: %s action: %s parameter %d";
-                        
-                        val message = String.format(
-                                messageFormat, 
-                                objectSpec.getFullIdentifier(), 
-                                objectAction.getName(), 
-                                paramNum);
-                        
-                        DeficiencyFacet.appendTo(
-                                objectSpec,
-                                objectSpec.getIdentifier(),
-                                message);
-                        
-                        return;
-                    }
-                }
-
-                val actionParameterChoicesFacet = parameter.getFacet(ActionParameterChoicesFacet.class);
-                val actionParameterAutoCompleteFacet = parameter.getFacet(ActionParameterAutoCompleteFacet.class);
-                if (actionParameterChoicesFacet != null || actionParameterAutoCompleteFacet != null) {
+        programmingModel.addVisitingValidatorSkipManagedBeans(objectSpec->{
+            // as an optimization only checking declared members (skipping inherited ones)  
+            objectSpec.streamDeclaredActions(MixedIn.INCLUDED)
+            .forEach(objectAction->{
+                if(objectAction instanceof ObjectActionMixedIn) {
+                    // we'll report only the mixin
                     return;
                 }
 
-                val parameterSpec = parameter.getSpecification();
-                if(parameterSpec.containsNonFallbackFacet(AutoCompleteFacet.class)) {
-                    return;
-                }
-                
-                //TODO[2253] remove this hotfix once ISIS-2253 is fixed
-                if(paramNum==0 && objectAction.containsNonFallbackFacet(AssociatedWithFacet.class)) {
-                    return; 
+                int paramNum = 0;
+                for (ObjectActionParameter parameter : objectAction.getParameters()) {
+                    if(parameter.getFeatureType() == FeatureType.ACTION_PARAMETER_COLLECTION) {
+                        validateActionParameter_whenCollection(
+                                objectSpec, objectAction, parameter, paramNum);
+                    }
+                    paramNum++;
                 }
+            });
+        });
+
+    }
+    
+    private static void validateActionParameter_whenCollection(
+            final ObjectSpecification objectSpec,
+            final ObjectAction objectAction,
+            final ObjectActionParameter parameter,
+            final int paramNum) {
+
+
+        val collectionSemanticsFacet = parameter.getFacet(CollectionSemanticsFacet.class);
+        if (collectionSemanticsFacet != null) {
+            // Violation if there are action parameter types that are assignable
+            // from java.util.Collection but are not of
+            // exact type List, Set, SortedSet or Collection.
+            if(!collectionSemanticsFacet.value().isSupportedInterfaceForActionParameters()) {
                 
-                val messageFormat = "Collection action parameter found without supporting "
-                        + "choices or autoComplete facet.  "
+                val messageFormat = "Collection action parameter found that is not exactly one "
+                        + "of the following supported types: "
+                        + "List, Set, SortedSet, Collection or Array.  "
                         + "Class: %s action: %s parameter %d";
                 
-                DeficiencyFacet.appendTo(
-                        objectSpec, 
+                ValidationFailure.raise(
+                        objectSpec,
                         String.format(
-                                messageFormat,
+                                messageFormat, 
                                 objectSpec.getFullIdentifier(), 
                                 objectAction.getName(), 
                                 paramNum));
+                
+                return;
             }
-        };
+        }
 
-        programmingModel.addValidatorSkipManagedBeans(vistingValidator);
+        val actionParameterChoicesFacet = parameter.getFacet(ActionParameterChoicesFacet.class);
+        val actionParameterAutoCompleteFacet = parameter.getFacet(ActionParameterAutoCompleteFacet.class);
+        if (actionParameterChoicesFacet != null || actionParameterAutoCompleteFacet != null) {
+            return;
+        }
 
+        val parameterSpec = parameter.getSpecification();
+        if(parameterSpec.containsNonFallbackFacet(AutoCompleteFacet.class)) {
+            return;
+        }
+        
+        //TODO[2253] remove this hotfix once ISIS-2253 is fixed
+        if(paramNum==0 && objectAction.containsNonFallbackFacet(AssociatedWithFacet.class)) {
+            return; 
+        }
+        
+        val messageFormat = "Collection action parameter found without supporting "
+                + "choices or autoComplete facet.  "
+                + "Class: %s action: %s parameter %d";
+        
+        ValidationFailure.raise(
+                objectSpec, 
+                String.format(
+                        messageFormat,
+                        objectSpec.getFullIdentifier(), 
+                        objectAction.getName(), 
+                        paramNum));
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/homepage/annotation/HomePageFacetAnnotationFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/homepage/annotation/HomePageFacetAnnotationFactory.java
index e8cbad4..45328e2 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/homepage/annotation/HomePageFacetAnnotationFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/homepage/annotation/HomePageFacetAnnotationFactory.java
@@ -33,16 +33,17 @@ import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.FacetedMethod;
 import org.apache.isis.core.metamodel.facets.actions.homepage.HomePageFacet;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting.Visitor;
+import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidator;
+import org.apache.isis.core.metamodel.specloader.validator.MetaModelVisitingValidatorAbstract;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 import static org.apache.isis.commons.internal.functions._Predicates.not;
 
+import lombok.NonNull;
 import lombok.val;
 
 public class HomePageFacetAnnotationFactory extends FacetFactoryAbstract
@@ -69,19 +70,22 @@ implements MetaModelRefiner {
 
     @Override
     public void refineProgrammingModel(ProgrammingModel programmingModel) {
-        programmingModel.addValidatorSkipManagedBeans(newValidatorVisitor());
+        programmingModel.addValidator(newValidatorVisitor());
     }
 
-    private Visitor newValidatorVisitor() {
-        return new MetaModelValidatorVisiting.SummarizingVisitor() {
-
+    private MetaModelValidator newValidatorVisitor() {
+        return new MetaModelVisitingValidatorAbstract() {
+            
             private final Map<String, ObjectAction> actionsHavingHomePageFacet = _Maps.newHashMap();
 
             @Override
-            public boolean visit(ObjectSpecification objectSpec) {
-                
+            public void validate(@NonNull ObjectSpecification spec) {
+                if(spec.isManagedBean()) {
+                    return;
+                }
+                             
                 // as an optimization only checking declared members (skipping inherited ones)                 
-                objectSpec.streamDeclaredActions(MixedIn.EXCLUDED)
+                spec.streamDeclaredActions(MixedIn.EXCLUDED)
                 .filter(objectAction->objectAction.containsFacet(HomePageFacet.class))
                 .forEach(objectAction->{
                     
@@ -95,8 +99,6 @@ implements MetaModelRefiner {
                     // TODO might collide with type level annotations as well 
                     
                 });
-
-                return true; // keep searching
             }
 
             @Override
@@ -114,7 +116,7 @@ implements MetaModelRefiner {
                                 .filter(not(actionId::equals))
                                 .collect(Collectors.joining(", "));
 
-                        DeficiencyFacet.appendTo(
+                        ValidationFailure.raise(
                                 objectAction, 
                                 String.format(
                                         "%s: other actions also specified as home page: %s ",
@@ -124,6 +126,8 @@ implements MetaModelRefiner {
                     }
                 }
             }
+
         };
+
     }
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java
index d6900ba..3062f01 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java
@@ -20,7 +20,6 @@ package org.apache.isis.core.metamodel.facets.actions.layout;
 
 import org.apache.isis.applib.annotation.ActionLayout;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
-import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.actions.position.ActionPositionFacet;
 import org.apache.isis.core.metamodel.facets.actions.position.ActionPositionFacetFallback;
@@ -37,7 +36,6 @@ import org.apache.isis.core.metamodel.facets.members.layout.order.LayoutOrderFac
 import org.apache.isis.core.metamodel.facets.members.layout.order.LayoutOrderFacetFromActionLayoutAnnotation;
 import org.apache.isis.core.metamodel.facets.object.bookmarkpolicy.BookmarkPolicyFacet;
 import org.apache.isis.core.metamodel.facets.object.promptStyle.PromptStyleFacet;
-import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorForAmbiguousMixinAnnotations;
 
 import lombok.val;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/deficiencies/DeficiencyFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/deficiencies/DeficiencyFacet.java
deleted file mode 100644
index 71114ef..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/all/deficiencies/DeficiencyFacet.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.isis.core.metamodel.facets.all.deficiencies;
-
-import org.apache.isis.applib.Identifier;
-import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facetapi.IdentifiedHolder;
-import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
-
-import lombok.AccessLevel;
-import lombok.NoArgsConstructor;
-import lombok.NonNull;
-import lombok.val;
-
-/**
- * Collects meta-model validation failures (deficiencies) directly with the holder that is involved.
- * @since 2.0
- */
-@NoArgsConstructor(access = AccessLevel.PRIVATE)
-public final class DeficiencyFacet {
-
-    /**
-     * Create a new DeficiencyFacet for the facetHolder (if it not already has one), 
-     * then adds given deficiency information to the facet. 
-     */
-    public static void appendTo(
-            @NonNull FacetHolder facetHolder, 
-            @NonNull Identifier deficiencyOrigin, 
-            @NonNull String deficiencyMessage) {
-        
-        val validationFailure = ValidationFailure.of(deficiencyOrigin, deficiencyMessage);
-        facetHolder.getSpecificationLoader().addValidationFailure(validationFailure);
-    }
-    
-    /**
-     * Create a new DeficiencyFacet for the facetHolder (if it not already has one), 
-     * then adds given deficiency information to the facet. 
-     */
-    public static void appendTo(
-            @NonNull IdentifiedHolder facetHolder, 
-            @NonNull String deficiencyMessage) {
-        appendTo(facetHolder, facetHolder.getIdentifier(), deficiencyMessage);
-    }
-    
-    /**
-     * Create a new DeficiencyFacet for the facetHolder (if it not already has one), 
-     * then adds given deficiency information to the facet. 
-     */
-    public static void appendToWithFormat(
-            @NonNull IdentifiedHolder facetHolder, 
-            @NonNull String messageFormat, 
-            final Object ...args) {
-        appendTo(facetHolder, String.format(messageFormat, args));
-    }
-
-}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/sortedby/annotation/SortedByFacetAnnotationFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/sortedby/annotation/SortedByFacetAnnotationFactory.java
index d503895..3da56a4 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/sortedby/annotation/SortedByFacetAnnotationFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/sortedby/annotation/SortedByFacetAnnotationFactory.java
@@ -25,19 +25,18 @@ import java.util.stream.Stream;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.collections.sortedby.SortedByFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 /**
  * There is no check that the value is a {@link Comparator}; 
  * instead this is done via {@link #refineProgrammingModel(ProgrammingModel)}.
  */
-public class SortedByFacetAnnotationFactory extends FacetFactoryAbstract
+public class SortedByFacetAnnotationFactory 
+extends FacetFactoryAbstract
 implements MetaModelRefiner {
 
     public SortedByFacetAnnotationFactory() {
@@ -54,40 +53,29 @@ implements MetaModelRefiner {
 
     @Override
     public void refineProgrammingModel(ProgrammingModel programmingModel) {
-        programmingModel.addValidatorSkipManagedBeans(newValidatorVisitor());
-    }
-
-    protected MetaModelValidatorVisiting.Visitor newValidatorVisitor() {
-        return new MetaModelValidatorVisiting.Visitor() {
-
-            @Override
-            public boolean visit(ObjectSpecification objectSpec) {
-                final Stream<OneToManyAssociation> objectCollections = 
-                        objectSpec.streamCollections(MixedIn.EXCLUDED);
+        programmingModel.addVisitingValidatorSkipManagedBeans(objectSpec->{
+            final Stream<OneToManyAssociation> objectCollections = 
+                    objectSpec.streamCollections(MixedIn.EXCLUDED);
 
-                objectCollections.forEach(objectCollection->{
-                    final SortedByFacet facet = objectCollection.getFacet(SortedByFacet.class);
-                    if(facet != null) {
-                        final Class<? extends Comparator<?>> cls = facet.value();
-                        if(!Comparator.class.isAssignableFrom(cls)) {
-                            
-                            DeficiencyFacet.appendTo(
-                                    objectSpec,
-                                    String.format(
-                                        "%s#%s: is annotated with @SortedBy, "
-                                        + "but the class specified '%s' is not a Comparator",
-                                        objectSpec.getIdentifier().getClassName(), 
-                                        objectCollection.getId(),
-                                        facet.value().getName()));
-                        }
+            objectCollections.forEach(objectCollection->{
+                final SortedByFacet facet = objectCollection.getFacet(SortedByFacet.class);
+                if(facet != null) {
+                    final Class<? extends Comparator<?>> cls = facet.value();
+                    if(!Comparator.class.isAssignableFrom(cls)) {
+                        
+                        ValidationFailure.raiseFormatted(
+                                objectSpec,
+                                String.format(
+                                    "%s#%s: is annotated with @SortedBy, "
+                                    + "but the class specified '%s' is not a Comparator",
+                                    objectSpec.getIdentifier().getClassName(), 
+                                    objectCollection.getId(),
+                                    facet.value().getName()));
                     }
-                });
-
-                return true;
-            }
-        };
+                }
+            });
+        });
     }
 
 
-
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/jaxb/JaxbFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/jaxb/JaxbFacetFactory.java
index 06048a8..9912cdd 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/jaxb/JaxbFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/jaxb/JaxbFacetFactory.java
@@ -42,7 +42,6 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.Annotations;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.object.recreatable.RecreatableObjectFacetForXmlRootElementAnnotation;
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
 import org.apache.isis.core.metamodel.facets.properties.update.modify.PropertySetterFacet;
@@ -50,7 +49,7 @@ import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 import static org.apache.isis.commons.internal.reflection._Reflect.Filter.isPublic;
 import static org.apache.isis.commons.internal.reflection._Reflect.Filter.paramCount;
@@ -170,45 +169,35 @@ implements MetaModelRefiner {
         final List<TypeValidator> typeValidators = getTypeValidators(getConfiguration());
         final List<PropertyValidator> propertyValidators = getPropertyValidators(getConfiguration());
 
-        programmingModel.addValidatorSkipManagedBeans(
-                new MetaModelValidatorVisiting.Visitor() {
-                    @Override
-                    public boolean visit(final ObjectSpecification objectSpec) {
-
-                        validate(objectSpec);
-                        return true;
-                    }
-
-                    private void validate(final ObjectSpecification objectSpec) {
-
-                        final boolean viewModel = objectSpec.isViewModel();
-                        if(!viewModel) {
-                            return;
-                        }
-
-                        final ViewModelFacet facet = objectSpec.getFacet(ViewModelFacet.class);
-                        if (!(facet instanceof RecreatableObjectFacetForXmlRootElementAnnotation)) {
-                            return;
-                        }
-
-                        for (final TypeValidator typeValidator : typeValidators) {
-                            typeValidator.validate(objectSpec);
-                        }
-
-                        final Stream<OneToOneAssociation> properties = objectSpec
-                                .streamProperties(MixedIn.EXCLUDED);
-
-                        properties
-                        // ignore derived
-                        .filter(property->property.containsNonFallbackFacet(PropertySetterFacet.class))
-                        .forEach(property->{
-                            for (final PropertyValidator adapterValidator : propertyValidators) {
-                                adapterValidator.validate(objectSpec, property);
-                            }
-                        });
-
-                    }
-                });
+        programmingModel.addVisitingValidatorSkipManagedBeans(objectSpec->{
+
+            final boolean viewModel = objectSpec.isViewModel();
+            if(!viewModel) {
+                return;
+            }
+
+            final ViewModelFacet facet = objectSpec.getFacet(ViewModelFacet.class);
+            if (!(facet instanceof RecreatableObjectFacetForXmlRootElementAnnotation)) {
+                return;
+            }
+
+            for (final TypeValidator typeValidator : typeValidators) {
+                typeValidator.validate(objectSpec);
+            }
+
+            final Stream<OneToOneAssociation> properties = objectSpec
+                    .streamProperties(MixedIn.EXCLUDED);
+
+            properties
+            // ignore derived
+            .filter(property->property.containsNonFallbackFacet(PropertySetterFacet.class))
+            .forEach(property->{
+                for (final PropertyValidator adapterValidator : propertyValidators) {
+                    adapterValidator.validate(objectSpec, property);
+                }
+            });
+
+        });
         
     }
 
@@ -277,7 +266,7 @@ implements MetaModelRefiner {
                 return;
             }
             final Class<?> propertyType = propertyTypeSpec.getCorrespondingClass();
-            DeficiencyFacet.appendToWithFormat(
+            ValidationFailure.raiseFormatted(
                     property,
                     "JAXB view model '%s' property '%s' is of type '%s' but that type is not annotated with @XmlJavaTypeAdapter.  The type must be annotated with @XmlJavaTypeAdapter(org.apache.isis.applib.jaxb.PersistentEntityAdapter.class) or equivalent.",
                     objectSpec.getFullIdentifier(),
@@ -318,7 +307,7 @@ implements MetaModelRefiner {
             }
 
             // else
-            DeficiencyFacet.appendToWithFormat(
+            ValidationFailure.raiseFormatted(
                     property,
                     "JAXB view model '%s' property '%s' is of type '%s' but is not annotated with @XmlJavaTypeAdapter.  The field/method must be annotated with @XmlJavaTypeAdapter(org.apache.isis.schema.utils.jaxbadapters.XxxAdapter.ForJaxb.class) or equivalent, or be ignored by being annotated with @XmlTransient.",
                     objectSpec.getFullIdentifier(),
@@ -333,7 +322,7 @@ implements MetaModelRefiner {
                 final ObjectSpecification objectSpec) {
 
             if(objectSpec.isAbstract()) {
-                DeficiencyFacet.appendTo(
+                ValidationFailure.raise(
                         objectSpec,
                         String.format("JAXB view model '%s' is abstract", objectSpec.getFullIdentifier())
                         );
@@ -348,17 +337,17 @@ implements MetaModelRefiner {
 
             final Class<?> correspondingClass = objectSpec.getCorrespondingClass();
             if(correspondingClass.isAnonymousClass()) {
-                DeficiencyFacet.appendToWithFormat(
+                ValidationFailure.raiseFormatted(
                         objectSpec,
                         "JAXB view model '%s' is an anonymous class", 
                         objectSpec.getFullIdentifier());
             } else if(correspondingClass.isLocalClass()) {
-                DeficiencyFacet.appendToWithFormat(
+                ValidationFailure.raiseFormatted(
                         objectSpec,
                         "JAXB view model '%s' is a local class", 
                         objectSpec.getFullIdentifier());
             } else if(correspondingClass.isMemberClass() && !Modifier.isStatic(correspondingClass.getModifiers())) {
-                DeficiencyFacet.appendToWithFormat(
+                ValidationFailure.raiseFormatted(
                         objectSpec,
                         "JAXB view model '%s' is an non-static inner class", 
                         objectSpec.getFullIdentifier());
@@ -385,12 +374,12 @@ implements MetaModelRefiner {
                     .filter(paramCount(0).and(isPublic().negate()));
             
             if(privateNoArgConstructors.isNotEmpty()) {
-                DeficiencyFacet.appendToWithFormat(
+                ValidationFailure.raiseFormatted(
                         objectSpec,
                         "JAXB view model '%s' has a no-arg constructor, however it is not public",
                         objectSpec.getFullIdentifier());
             } else {
-                DeficiencyFacet.appendToWithFormat(
+                ValidationFailure.raiseFormatted(
                         objectSpec,
                         "JAXB view model '%s' does not have a public no-arg constructor", 
                         objectSpec.getFullIdentifier());
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactory.java
index ae34683..1f75271 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactory.java
@@ -28,7 +28,7 @@ import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facets.Annotations;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 import lombok.val;
 
@@ -65,8 +65,8 @@ extends FacetFactoryAbstract {
         final boolean annotatedWithDomainObject = domainObject != null;
 
         if(implementsViewModel && implementsRecreatableDomainObject) {
-            DeficiencyFacet.appendTo(
-                    facetHolder,
+            ValidationFailure.raise(
+                    facetHolder.getSpecificationLoader(),
                     Identifier.classIdentifier(LogicalType.fqcn(cls)),
                     String.format(
                         "Inconsistent view model / domain object semantics; %s should not implement "
@@ -78,8 +78,8 @@ extends FacetFactoryAbstract {
 
         }
         if(implementsViewModel && annotatedWithDomainObject) {
-            DeficiencyFacet.appendTo(
-                    facetHolder,
+            ValidationFailure.raise(
+                    facetHolder.getSpecificationLoader(),
                     Identifier.classIdentifier(LogicalType.fqcn(cls)),
                     String.format(
                         "Inconsistent view model / domain object semantics; %1$s should not implement "
@@ -92,8 +92,8 @@ extends FacetFactoryAbstract {
                     );
         }
         if(implementsViewModel && annotatedWithDomainObjectLayout) {
-            DeficiencyFacet.appendTo(
-                    facetHolder,
+            ValidationFailure.raise(
+                    facetHolder.getSpecificationLoader(),
                     Identifier.classIdentifier(LogicalType.fqcn(cls)),
                     String.format(
                         "Inconsistent view model / domain object semantics; %1$s should not implement "
@@ -109,8 +109,8 @@ extends FacetFactoryAbstract {
                 && (domainObject.nature() == Nature.NOT_SPECIFIED 
                     || domainObject.nature().isEntity()) 
                 && implementsRecreatableDomainObject) {
-            DeficiencyFacet.appendTo(
-                    facetHolder,
+            ValidationFailure.raise(
+                    facetHolder.getSpecificationLoader(),
                     Identifier.classIdentifier(LogicalType.fqcn(cls)),
                     String.format(
                         "Inconsistent view model / domain object semantics; %1$s should not be annotated with "
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/bookmarkpolicy/bookmarkable/BookmarkPolicyFacetFallbackFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/bookmarkpolicy/bookmarkable/BookmarkPolicyFacetFallbackFactory.java
index 1170e00..6da9d4d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/bookmarkpolicy/bookmarkable/BookmarkPolicyFacetFallbackFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/bookmarkpolicy/bookmarkable/BookmarkPolicyFacetFallbackFactory.java
@@ -24,11 +24,11 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.actions.semantics.ActionSemanticsFacet;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.object.bookmarkpolicy.BookmarkPolicyFacet;
 import org.apache.isis.core.metamodel.facets.object.bookmarkpolicy.BookmarkPolicyFacetFallback;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 public class BookmarkPolicyFacetFallbackFactory extends FacetFactoryAbstract
 implements MetaModelRefiner {
@@ -53,7 +53,7 @@ implements MetaModelRefiner {
     @Override
     public void refineProgrammingModel(ProgrammingModel programmingModel) {
         
-        programmingModel.addValidatorSkipManagedBeans(objectSpec -> {
+        programmingModel.addVisitingValidatorSkipManagedBeans(objectSpec -> {
 
             // as an optimization only checking declared members (skipping inherited ones)
             objectSpec.streamDeclaredActions(MixedIn.EXCLUDED)
@@ -68,7 +68,7 @@ implements MetaModelRefiner {
             .forEach(objectAction->{
                 final ActionSemanticsFacet semanticsFacet = objectAction.getFacet(ActionSemanticsFacet.class);
                 if(semanticsFacet == null || semanticsFacet.isFallback() || !semanticsFacet.value().isSafeInNature()) {
-                    DeficiencyFacet.appendToWithFormat(
+                    ValidationFailure.raiseFormatted(
                             objectAction,
                             "%s: action is bookmarkable but action semantics are not explicitly indicated as being safe.  " +
                                     "Either add @Action(semantics=SemanticsOf.SAFE) or @Action(semantics=SemanticsOf.SAFE_AND_REQUEST_CACHEABLE), or remove @ActionLayout(bookmarking=...).",
@@ -76,8 +76,6 @@ implements MetaModelRefiner {
                 }
             });
 
-            return true;
-            
         });
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
index b2d4e17..47638de 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
@@ -52,7 +52,6 @@ import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.MethodFinderUtils;
 import org.apache.isis.core.metamodel.facets.ObjectSpecIdFacetFactory;
 import org.apache.isis.core.metamodel.facets.PostConstructMethodCache;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.object.autocomplete.AutoCompleteFacet;
 import org.apache.isis.core.metamodel.facets.object.callbacks.CreatedLifecycleEventFacetForDomainObjectAnnotation;
 import org.apache.isis.core.metamodel.facets.object.callbacks.LoadedLifecycleEventFacetForDomainObjectAnnotation;
@@ -76,7 +75,8 @@ import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacetForDomainObj
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
+import org.apache.isis.core.metamodel.specloader.validator.MetaModelVisitingValidatorAbstract;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 import org.apache.isis.core.metamodel.util.EventUtil;
 
 import static org.apache.isis.commons.internal.base._NullSafe.stream;
@@ -210,8 +210,8 @@ implements MetaModelRefiner, PostConstructMethodCache, ObjectSpecIdFacetFactory
                 }
             }
         }
-        DeficiencyFacet.appendTo(
-                facetHolder,
+        ValidationFailure.raise(
+                facetHolder.getSpecificationLoader(),
                 Identifier.classIdentifier(LogicalType.fqcn(cls)),
                 String.format(
                         "%s annotation on %s specifies method '%s' that does not exist in repository '%s'",
@@ -484,13 +484,15 @@ implements MetaModelRefiner, PostConstructMethodCache, ObjectSpecIdFacetFactory
         final _Multimaps.ListMultimap<String, ObjectSpecification> collidingSpecsByLogicalTypeName =
                 _Multimaps.newConcurrentListMultimap();
 
-        final MetaModelValidatorVisiting.SummarizingVisitor ensureUniqueObjectIds =
-                new MetaModelValidatorVisiting.SummarizingVisitor(){
+        final MetaModelVisitingValidatorAbstract ensureUniqueObjectIds =
+                new MetaModelVisitingValidatorAbstract(){
 
                     @Override
-                    public boolean visit(ObjectSpecification objSpec) {
+                    public void validate(ObjectSpecification objSpec) {
+                        if(objSpec.isManagedBean()) {
+                            return;
+                        }
                         collidingSpecsByLogicalTypeName.putElement(objSpec.getLogicalTypeName() , objSpec);
-                        return true;
                     }
 
                     @Override
@@ -502,7 +504,7 @@ implements MetaModelRefiner, PostConstructMethodCache, ObjectSpecIdFacetFactory
                                 val csv = asCsv(collidingSpecs);
 
                                 collidingSpecs.forEach(spec->{
-                                    DeficiencyFacet.appendToWithFormat(
+                                    ValidationFailure.raiseFormatted(
                                             spec,
                                             "Logical-type-name (aka. object-type) '%s' mapped to multiple classes: %s",
                                             logicalTypeName,
@@ -524,7 +526,7 @@ implements MetaModelRefiner, PostConstructMethodCache, ObjectSpecIdFacetFactory
 
                 };
 
-        pm.addValidatorSkipManagedBeans(ensureUniqueObjectIds);
+        pm.addValidator(ensureUniqueObjectIds);
     }
 
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservice/annotation/DomainServiceFacetAnnotationFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservice/annotation/DomainServiceFacetAnnotationFactory.java
index 83c6639..c797cf2 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservice/annotation/DomainServiceFacetAnnotationFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainservice/annotation/DomainServiceFacetAnnotationFactory.java
@@ -26,13 +26,14 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.Annotations;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.object.domainservice.DomainServiceFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
+import org.apache.isis.core.metamodel.specloader.validator.MetaModelVisitingValidator;
+import org.apache.isis.core.metamodel.specloader.validator.MetaModelVisitingValidatorAbstract;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 import lombok.val;
 
@@ -66,15 +67,10 @@ implements MetaModelRefiner {
     @Override
     public void refineProgrammingModel(ProgrammingModel programmingModel) {
         
-        programmingModel.addValidatorSkipManagedBeans(new MetaModelValidatorVisiting.Visitor() {
+        programmingModel.addValidator(new MetaModelVisitingValidatorAbstract() {
 
             @Override
-            public boolean visit(final ObjectSpecification thisSpec) {
-                validate(thisSpec);
-                return true;
-            }
-
-            private void validate(final ObjectSpecification objectSpec) {
+            public void validate(final ObjectSpecification objectSpec) {
 
                 if(!objectSpec.containsFacet(DomainServiceFacet.class)) {
                     return;
@@ -91,7 +87,7 @@ implements MetaModelRefiner {
                     return;
                 }
 
-                DeficiencyFacet.appendToWithFormat(
+                ValidationFailure.raiseFormatted(
                         objectSpec,
                         "%s: services can only have actions ('%s' config property), not properties or collections; annotate with @Programmatic if required.  Found: %s",
                         objectSpec.getFullIdentifier(),
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MetaModelValidatorForMixinTypes.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MetaModelValidatorForMixinTypes.java
index 9eccf74..bafb7e3 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MetaModelValidatorForMixinTypes.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MetaModelValidatorForMixinTypes.java
@@ -22,7 +22,7 @@ import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.internal.reflection._Reflect;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 import static org.apache.isis.commons.internal.reflection._Reflect.Filter.paramCount;
 
@@ -50,8 +50,8 @@ public class MetaModelValidatorForMixinTypes {
         }
         
         if(mixinContructors.getCardinality().isZero()) {
-            DeficiencyFacet.appendTo(
-                    facetHolder,
+            ValidationFailure.raise(
+                    facetHolder.getSpecificationLoader(),
                     Identifier.classIdentifier(LogicalType.fqcn(candidateMixinType)),
                     String.format(
                         "%s: annotated with %s annotation but does not have a public 1-arg constructor",
@@ -59,8 +59,8 @@ public class MetaModelValidatorForMixinTypes {
                         annotation)
                     );
         } else {
-            DeficiencyFacet.appendTo(
-                    facetHolder,
+            ValidationFailure.raise(
+                    facetHolder.getSpecificationLoader(),
                     Identifier.classIdentifier(LogicalType.fqcn(candidateMixinType)),
                     String.format(
                             "%s: annotated with %s annotation needs a single public 1-arg constructor but has %d",
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/navparent/annotation/NavigableParentAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/navparent/annotation/NavigableParentAnnotationFacetFactory.java
index 6a8b7be..29d5285 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/navparent/annotation/NavigableParentAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/navparent/annotation/NavigableParentAnnotationFacetFactory.java
@@ -29,9 +29,9 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.Annotations;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.object.navparent.method.NavigableParentFacetMethod;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 import lombok.extern.log4j.Log4j2;
 
@@ -110,27 +110,26 @@ implements MetaModelRefiner {
     @Override
     public void refineProgrammingModel(ProgrammingModel programmingModel) {
 
-        programmingModel.addValidatorSkipManagedBeans(objectSpec -> {
-
-
-            final Class<?> cls = objectSpec.getCorrespondingClass();
+        programmingModel.addVisitingValidatorSkipManagedBeans(spec->{
+                
+            final Class<?> cls = spec.getCorrespondingClass();
 
             final List<Annotations.Evaluator<PropertyLayout>> evaluators =
                     Annotations.firstEvaluatorsInHierarchyHaving(cls, PropertyLayout.class,
                             NavigableParentAnnotationFacetFactory::isNavigableParentFlagSet);
 
             if (_NullSafe.isEmpty(evaluators)) {
-                return true; // no conflict, continue validation processing
+                return; // no conflict, continue validation processing
             } else if (evaluators.size()>1) {
 
-                DeficiencyFacet.appendToWithFormat(
-                        objectSpec,
+                ValidationFailure.raiseFormatted(
+                        spec,
                         "%s: conflict for determining a strategy for retrieval of (navigable) parent for class, "
                                 + "contains multiple annotations '@%s' having navigable=PARENT, while at most one is allowed.",
-                                objectSpec.getIdentifier().getClassName(),
+                                spec.getIdentifier().getClassName(),
                                 PropertyLayout.class.getName());
 
-                return true; // continue validation processing
+                return; // continue validation processing
             }
 
             final Annotations.Evaluator<PropertyLayout> parentEvaluator = evaluators.get(0);
@@ -143,21 +142,19 @@ implements MetaModelRefiner {
 
                 if(!fieldEvaluator.getGetter(cls).isPresent()) {
 
-                    DeficiencyFacet.appendToWithFormat(
-                            objectSpec,
+                    ValidationFailure.raiseFormatted(
+                            spec,
                             "%s: unable to determine a strategy for retrieval of (navigable) parent for class, "
                                     + "field '%s' annotated with '@%s' having navigable=PARENT does not provide a getter.",
-                                    objectSpec.getIdentifier().getClassName(),
+                                    spec.getIdentifier().getClassName(),
                                     fieldEvaluator.getField().getName(),
                                     PropertyLayout.class.getName());
                 }
 
             }
-
-
-            return true; //continue validation processing
-
+            
         });
+
     }
 
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdMalformedValidator.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdMalformedValidator.java
index c9140ae..a2b938a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdMalformedValidator.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdMalformedValidator.java
@@ -21,10 +21,8 @@ package org.apache.isis.core.metamodel.facets.object.objectspecid;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 import lombok.val;
 
@@ -41,48 +39,37 @@ implements MetaModelRefiner {
     @Override
     public void refineProgrammingModel(ProgrammingModel programmingModel) {
         
-        programmingModel.addValidatorIncludeManagedBeans(
-
-            new MetaModelValidatorVisiting.Visitor() {
-                
-                @Override
-                public boolean visit(ObjectSpecification objectSpec) {
-                    
-                    if(objectSpec.isEntityOrViewModel()
-                            || objectSpec.isManagedBean() ) {
-                        validate(objectSpec);    
-                    }
-                    return true;
-                }
-    
-                private void validate(
-                        ObjectSpecification objectSpec) {
+        programmingModel.addVisitingValidator(spec->{
                     
-                    val objectSpecIdFacet = objectSpec.getFacet(ObjectSpecIdFacet.class);
-                    if(objectSpecIdFacet == null) {
-                        return;
-                    }
-                    
-                    val logicalTypeName = objectSpecIdFacet.value();
-                    
-                    val nameParts = _Strings.splitThenStream(logicalTypeName, ".")
-                            .collect(Can.toCan());
-                    
-                    if(!nameParts.getCardinality().isMultiple()
-                            || nameParts.stream()
-                                .anyMatch(String::isEmpty)) {
-                        
-                        DeficiencyFacet.appendToWithFormat(
-                                objectSpec,
-                                "%s: the object type must declare a namespace, yet was found to be invalid '%s'; "
-                                + "eg. @DomainObject(objectType=\"Customer\") is considered invalid, "
-                                + "whereas @DomainObject(objectType=\"sales.Customer\") is valid.",
-                                objectSpec.getFullIdentifier(),
-                                logicalTypeName);
-                    }
-                }
+            if(!spec.isEntityOrViewModel()
+                    && !spec.isManagedBean() ) {
+                return;   
+            }
+            
+            val objectSpecIdFacet = spec.getFacet(ObjectSpecIdFacet.class);
+            if(objectSpecIdFacet == null) {
+                return;
+            }
+            
+            val logicalTypeName = objectSpecIdFacet.value();
+            
+            val nameParts = _Strings.splitThenStream(logicalTypeName, ".")
+                    .collect(Can.toCan());
+            
+            if(!nameParts.getCardinality().isMultiple()
+                    || nameParts.stream()
+                        .anyMatch(String::isEmpty)) {
+                
+                ValidationFailure.raiseFormatted(
+                        spec,
+                        "%s: the object type must declare a namespace, yet was found to be invalid '%s'; "
+                        + "eg. @DomainObject(objectType=\"Customer\") is considered invalid, "
+                        + "whereas @DomainObject(objectType=\"sales.Customer\") is valid.",
+                        spec.getFullIdentifier(),
+                        logicalTypeName);
+            }
     
-            });
+        });
 
     }
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java
index 339da6f..93486d1 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java
@@ -30,7 +30,6 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.ObjectSpecIdFacetFactory;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.object.domainservice.DomainServiceFacet;
 import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
@@ -38,7 +37,7 @@ import org.apache.isis.core.metamodel.services.classsubstitutor.ClassSubstitutor
 import org.apache.isis.core.metamodel.services.classsubstitutor.ClassSubstitutorRegistry;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 import lombok.val;
 
@@ -112,39 +111,26 @@ implements MetaModelRefiner, ObjectSpecIdFacetFactory {
             return;
         }
 
-        programmingModel.addValidatorSkipManagedBeans(
-
-            new MetaModelValidatorVisiting.Visitor() {
-                
-                @Override
-                public boolean visit(ObjectSpecification objectSpec) {
-                    validate(objectSpec);
-                    return true;
-                }
-    
-                private void validate(ObjectSpecification objectSpec) {
+        programmingModel.addVisitingValidatorSkipManagedBeans(objectSpec-> {
                     
-                    if(skip(objectSpec)) {
-                        return;
-                    }
-                    val objectSpecIdFacet = objectSpec.getFacet(ObjectSpecIdFacet.class);
-                    if(objectSpecIdFacet instanceof ObjectSpecIdFacetDerivedFromClassName) {
-                        DeficiencyFacet.appendToWithFormat(
-                                objectSpec,
-                                "%s: the object type must be specified explicitly ('%s' config property). "
-                                        + "Defaulting the object type from the package/class/package name can lead "
-                                        + "to data migration issues for apps deployed to production (if the class is "
-                                        + "subsequently refactored). "
-                                        + "Use @Discriminator, @DomainObject(objectType=...) or "
-                                        + "@PersistenceCapable(schema=...) to specify explicitly.",
-                                objectSpec.getFullIdentifier(),
-                                "isis.core.meta-model.validator.explicit-object-type");
-                    } 
-                }
-    
-                private boolean skip(ObjectSpecification objectSpec) {
-                    return !check(objectSpec);
-                }
+            if(!check(objectSpec)) {
+                return;
+            }
+            
+            val objectSpecIdFacet = objectSpec.getFacet(ObjectSpecIdFacet.class);
+            if(objectSpecIdFacet instanceof ObjectSpecIdFacetDerivedFromClassName) {
+                ValidationFailure.raiseFormatted(
+                        objectSpec,
+                        "%s: the object type must be specified explicitly ('%s' config property). "
+                                + "Defaulting the object type from the package/class/package name can lead "
+                                + "to data migration issues for apps deployed to production (if the class is "
+                                + "subsequently refactored). "
+                                + "Use @Discriminator, @DomainObject(objectType=...) or "
+                                + "@PersistenceCapable(schema=...) to specify explicitly.",
+                        objectSpec.getFullIdentifier(),
+                        "isis.core.meta-model.validator.explicit-object-type");
+            } 
+                
             });
 
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactory.java
index ef3348f..e7a4cc9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactory.java
@@ -29,7 +29,6 @@ import javax.xml.bind.annotation.XmlRootElement;
 import org.apache.isis.applib.RecreatableDomainObject;
 import org.apache.isis.applib.ViewModel;
 import org.apache.isis.commons.internal.collections._Maps;
-import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facetapi.FacetUtil;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
@@ -38,9 +37,9 @@ import org.apache.isis.core.metamodel.facets.Annotations;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.MethodFinderUtils;
 import org.apache.isis.core.metamodel.facets.PostConstructMethodCache;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 import lombok.val;
 
@@ -53,7 +52,7 @@ implements MetaModelRefiner, PostConstructMethodCache {
 
     /**
      * We simply attach all facets we can find; 
-     * the {@link #refineMetaModelValidator(org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorComposite, IsisConfiguration) meta-model validation} 
+     * the {@link #refineProgrammingModel(ProgrammingModel) meta-model validation} 
      * will detect if multiple interfaces/annotations have
      * been attached.
      */
@@ -97,15 +96,15 @@ implements MetaModelRefiner, PostConstructMethodCache {
     @Override
     public void refineProgrammingModel(ProgrammingModel programmingModel) {
 
-        programmingModel.addValidatorSkipManagedBeans(objectSpec -> {
+        programmingModel.addVisitingValidatorSkipManagedBeans(objectSpec -> {
 
             val viewModelFacet = objectSpec.getFacet(ViewModelFacet.class);
             val underlyingFacet = viewModelFacet != null ? viewModelFacet.getUnderlyingFacet() : null;
             if(underlyingFacet == null) {
-                return true;    
+                return;    
             }
             if(underlyingFacet.getClass() != viewModelFacet.getClass()) {
-                DeficiencyFacet.appendToWithFormat(
+                ValidationFailure.raiseFormatted(
                         objectSpec,
                         "%s: has multiple incompatible annotations/interfaces indicating that " +
                                 "it is a recreatable object of some sort (%s and %s)",
@@ -113,7 +112,6 @@ implements MetaModelRefiner, PostConstructMethodCache {
                                 viewModelFacet.getClass().getSimpleName(),
                                 underlyingFacet.getClass().getSimpleName());
             }
-            return true;
         });
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleAnnotationFacetFactory.java
index c6bea79..e080269 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleAnnotationFacetFactory.java
@@ -35,10 +35,10 @@ import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.Annotations;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.MethodFinderUtils;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.fallback.FallbackFacetFactory;
 import org.apache.isis.core.metamodel.facets.object.title.methods.TitleFacetViaMethodsFactory;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 public class TitleAnnotationFacetFactory extends FacetFactoryAbstract
 implements MetaModelRefiner {
@@ -150,25 +150,25 @@ implements MetaModelRefiner {
     @Override
     public void refineProgrammingModel(ProgrammingModel programmingModel) {
 
-        programmingModel.addValidatorSkipManagedBeans(objectSpec -> {
+        programmingModel.addVisitingValidatorSkipManagedBeans(objectSpec -> {
 
             final Class<?> cls = objectSpec.getCorrespondingClass();
 
             final Method titleMethod = MethodFinderUtils.findMethod(cls, TITLE_METHOD_NAME, String.class, null);
             if (titleMethod == null) {
-                return true;
+                return;
             }
 
             // determine if cls contains an @Title annotated method, not inherited from superclass
             final Class<?> supClass = cls.getSuperclass();
             if (supClass == null) {
-                return true;
+                return;
             }
 
             final List<Method> methods = methodsWithTitleAnnotation(cls);
             final List<Method> superClassMethods = methodsWithTitleAnnotation(supClass);
             if (methods.size() > superClassMethods.size()) {
-                DeficiencyFacet.appendToWithFormat(
+                ValidationFailure.raiseFormatted(
                         objectSpec,
                         "%s: conflict for determining a strategy for retrieval of title for class, contains a method '%s' and an annotation '@%s'",
                         objectSpec.getIdentifier().getClassName(),
@@ -176,8 +176,6 @@ implements MetaModelRefiner {
                         Title.class.getName());
             }
 
-            return true;
-
         });
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodel/ProgrammingModel.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodel/ProgrammingModel.java
index 50145c7..bda846f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodel/ProgrammingModel.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodel/ProgrammingModel.java
@@ -19,7 +19,7 @@
 
 package org.apache.isis.core.metamodel.progmodel;
 
-import java.util.function.Predicate;
+import java.util.function.Consumer;
 import java.util.function.Supplier;
 import java.util.stream.Stream;
 
@@ -27,7 +27,7 @@ import org.apache.isis.commons.internal.functions._Functions;
 import org.apache.isis.core.metamodel.facets.FacetFactory;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidator;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
+import org.apache.isis.core.metamodel.specloader.validator.MetaModelVisitingValidatorAbstract;
 
 import lombok.NonNull;
 
@@ -147,32 +147,40 @@ public interface ProgrammingModel {
     
     /** shortcut for see {@link #addValidator(ValidationOrder, MetaModelValidator, Marker...)} */
     default void addValidator(
-            MetaModelValidator validator, 
+            final @NonNull MetaModelValidator validator, 
             Marker ... markers) {
         
-        final Supplier<MetaModelValidator> supplier = ()->validator;
-        addValidator(ValidationOrder.A2_AFTER_BUILTIN, supplier.get(), markers);
-    }
-
-    /** do include managed beans */
-    default void addValidatorIncludeManagedBeans(MetaModelValidatorVisiting.Visitor visitor, Marker ... markers) {
-        addValidator(MetaModelValidatorVisiting.of(visitor, 
-                    spec -> !spec.getBeanSort().isUnknown()),
-                markers);
+        addValidator(ValidationOrder.A2_AFTER_BUILTIN, validator, markers);
     }
     
-    /** do not include managed beans */
-    default void addValidatorSkipManagedBeans(MetaModelValidatorVisiting.Visitor visitor, Marker ... markers) {
-        addValidator(MetaModelValidatorVisiting.of(visitor, 
-                    spec -> !spec.isManagedBean() && !spec.getBeanSort().isUnknown()),
-                markers);
+    default void addVisitingValidator(
+            final @NonNull Consumer<ObjectSpecification> validator, 
+            Marker ... markers) {
+        
+        addValidator(new MetaModelVisitingValidatorAbstract() {
+            @Override
+            public void validate(@NonNull ObjectSpecification spec) {
+                validator.accept(spec);
+            }
+        });
     }
     
-    default void addValidator(final MetaModelValidatorVisiting.Visitor visitor,
-                              final @NonNull Predicate<ObjectSpecification> specPredicate,
-                              final Marker ... markers) {
-        addValidator(MetaModelValidatorVisiting.of(visitor, specPredicate), markers);
+    default void addVisitingValidatorSkipManagedBeans(
+            final @NonNull Consumer<ObjectSpecification> validator, 
+            Marker ... markers) {
+        
+        addValidator(new MetaModelVisitingValidatorAbstract() {
+            @Override
+            public void validate(@NonNull ObjectSpecification spec) {
+                if(spec.isManagedBean()) {
+                    return;
+                }
+                validator.accept(spec);
+            }
+        });
     }
+    
+    
 
     /** shortcut for see {@link #addPostProcessor(PostProcessingOrder, ObjectSpecificationPostProcessor, Marker...)}*/
     default <T extends ObjectSpecificationPostProcessor> void addPostProcessor(
@@ -185,4 +193,6 @@ public interface ProgrammingModel {
     }
 
     
+
+    
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
index 77ce49f..7b9be93 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
@@ -32,7 +32,6 @@ import org.apache.isis.core.metamodel.facets.actions.homepage.annotation.HomePag
 import org.apache.isis.core.metamodel.facets.actions.layout.ActionLayoutFacetFactory;
 import org.apache.isis.core.metamodel.facets.actions.notinservicemenu.derived.NotInServiceMenuFacetDerivedFromDomainServiceFacetFactory;
 import org.apache.isis.core.metamodel.facets.actions.validate.method.ActionValidationFacetViaMethodFactory;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.all.i18n.TranslationFacetFactory;
 import org.apache.isis.core.metamodel.facets.collections.accessor.CollectionAccessorFacetViaAccessorFactory;
 import org.apache.isis.core.metamodel.facets.collections.collection.CollectionAnnotationFacetFactory;
@@ -147,9 +146,13 @@ import org.apache.isis.core.metamodel.facets.value.uuid.UUIDValueFacetUsingSeman
 import org.apache.isis.core.metamodel.postprocessors.param.DeriveFacetsPostProcessor;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModelAbstract;
 import org.apache.isis.core.metamodel.services.title.TitlesAndTranslationsValidator;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.specloader.validator.MetaModelVisitingValidatorAbstract;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
+import lombok.NonNull;
 import lombok.val;
 
 public final class ProgrammingModelFacetsJava8 extends ProgrammingModelAbstract {
@@ -357,27 +360,37 @@ public final class ProgrammingModelFacetsJava8 extends ProgrammingModelAbstract
         addPostProcessor(PostProcessingOrder.A1_BUILTIN, DeriveFacetsPostProcessor.class);
         addValidator(new TitlesAndTranslationsValidator());
 
-        addValidator(objectSpec -> {
-            
-            val actions = objectSpec.streamActions(MixedIn.INCLUDED).collect(Collectors.toList());
-            
-            final int numActions = actions.size();
-            if (numActions > 0) {
-
-                val actionIds = actions.stream()
-                .map(ObjectAction::getIdentifier)
-                .map(Identifier::toString)
-                .collect(Collectors.joining(", "));
-
-                DeficiencyFacet.appendToWithFormat(
-                        objectSpec,
-                        "%s: is a (concrete) but UNKNOWN sort, yet has %d actions: {%s}",
-                        objectSpec.getCorrespondingClass().getName(),
-                        numActions,
-                        actionIds);
+        addValidator(new MetaModelVisitingValidatorAbstract() {
+
+            @Override
+            public void validate(@NonNull ObjectSpecification spec) {
+                
+                if(spec.getBeanSort()==BeanSort.UNKNOWN 
+                        && !spec.isAbstract()) {
+                    return;
+                }
+                
+                val actions = spec.streamActions(MixedIn.INCLUDED).collect(Collectors.toList());
+                
+                final int numActions = actions.size();
+                if (numActions > 0) {
+
+                    val actionIds = actions.stream()
+                    .map(ObjectAction::getIdentifier)
+                    .map(Identifier::toString)
+                    .collect(Collectors.joining(", "));
+
+                    ValidationFailure.raiseFormatted(
+                            spec,
+                            "%s: is a (concrete) but UNKNOWN sort, yet has %d actions: {%s}",
+                            spec.getCorrespondingClass().getName(),
+                            numActions,
+                            actionIds);
+                }
+                
             }
-            return false;
-        }, objectSpec -> objectSpec.getBeanSort() == BeanSort.UNKNOWN && ! objectSpec.isAbstract());
+            
+        });
 
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/title/TitlesAndTranslationsValidator.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/title/TitlesAndTranslationsValidator.java
index 8944b56..1bf37eb 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/title/TitlesAndTranslationsValidator.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/title/TitlesAndTranslationsValidator.java
@@ -24,8 +24,8 @@ import org.apache.isis.applib.services.i18n.TranslationContext;
 import org.apache.isis.applib.services.title.TitleService;
 import org.apache.isis.commons.internal.base._Blackhole;
 import org.apache.isis.core.config.messages.MessageRegistry;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorAbstract;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 import lombok.val;
 
@@ -34,7 +34,8 @@ import lombok.val;
  * @since 2.0
  *
  */
-public class TitlesAndTranslationsValidator extends MetaModelValidatorAbstract {
+public class TitlesAndTranslationsValidator 
+extends MetaModelValidatorAbstract {
 
     @Override
     public void validate() {
@@ -63,8 +64,8 @@ public class TitlesAndTranslationsValidator extends MetaModelValidatorAbstract {
                         LogicalType.eager(managedBeanAdapter.getBeanClass(), objectType));
                 val facetHolder = specificationLoader.loadSpecification(managedBeanAdapter.getBeanClass());
                 
-                DeficiencyFacet.appendTo(
-                        facetHolder, 
+                ValidationFailure.raise(
+                        facetHolder.getSpecificationLoader(), 
                         deficiencyOrigin, 
                         String.format(
                                 "Failed to get instance of service bean %s", 
@@ -86,8 +87,8 @@ public class TitlesAndTranslationsValidator extends MetaModelValidatorAbstract {
                         LogicalType.eager(managedBeanAdapter.getBeanClass(), objectType));
                 val facetHolder = specificationLoader.loadSpecification(managedBeanAdapter.getBeanClass());
 
-                DeficiencyFacet.appendTo(
-                        facetHolder, 
+                ValidationFailure.raise(
+                        facetHolder.getSpecificationLoader(), 
                         deficiencyOrigin, 
                         String.format(
                                 "Failed to get title for service bean %s", 
@@ -124,8 +125,8 @@ public class TitlesAndTranslationsValidator extends MetaModelValidatorAbstract {
                         val deficiencyOrigin = Identifier.classIdentifier(objSpec.getLogicalType());
                         val facetHolder = objSpec;
 
-                        DeficiencyFacet.appendTo(
-                                facetHolder, 
+                        ValidationFailure.raise(
+                                facetHolder.getSpecificationLoader(), 
                                 deficiencyOrigin, 
                                 String.format(
                                         "Failed to get title for enum constant %s", 
@@ -162,8 +163,8 @@ public class TitlesAndTranslationsValidator extends MetaModelValidatorAbstract {
                 val spec = specificationLoader.loadSpecification(MessageRegistry.class);
                 val deficiencyOrigin = Identifier.classIdentifier(spec.getLogicalType());
 
-                DeficiencyFacet.appendTo(
-                        spec, 
+                ValidationFailure.raise(
+                        spec.getSpecificationLoader(), 
                         deficiencyOrigin, 
                         String.format(
                                 "Failed to translate message %s from MessageRegistry", 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
index 53e436d..03569ad 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
@@ -468,12 +468,13 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
     
     @Override
     public void addValidationFailure(ValidationFailure validationFailure) {
-        if(validationResult.isMemoized()) {
-            throw _Exceptions.illegalState(
-                    "Validation result was already created and can no longer be modified.");
-        }
+//        if(validationResult.isMemoized()) {
+//            validationResult.clear(); // invalidate
+////            throw _Exceptions.illegalState(
+////                    "Validation result was already created and can no longer be modified.");
+//        }
         synchronized(validationFailures) {
-            validationFailures.add(validationFailure);;
+            validationFailures.add(validationFailure);
         }
     }
     
@@ -490,6 +491,7 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
         .map(MetaModelValidatorAbstract.class::cast)
         .forEach(validator -> {
             log.debug("Running validator: {}", validator);
+            validator.setMetaModelContext(metaModelContext);
             try {
                 validator.validate();
             } catch (Throwable t) {
@@ -506,6 +508,7 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
         return validationFailures;
     }
 
+
     // -- HELPER
     
     @Nullable
@@ -646,4 +649,6 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
         }
     }
 
+   
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidator.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidator.java
index a507865..0e75d7c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidator.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidator.java
@@ -21,14 +21,6 @@ package org.apache.isis.core.metamodel.specloader.validator;
 
 public interface MetaModelValidator {
 
-    /**
-     * Collect any {@link ValidationFailure} to given validationFailures. 
-     *  
-     * @param validationFailures
-     */
-    //void collectFailuresInto(@NonNull ValidationFailures validationFailures);
-    
     void validate();
     
-    
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorAbstract.java
index 8bf3c81..f21964d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorAbstract.java
@@ -31,31 +31,9 @@ implements
     MetaModelValidator, 
     MetaModelContextAware {
 
-    //protected final ValidationFailures failures = new ValidationFailures();
-    
     @Getter @Setter(onMethod = @__(@Override))
     private MetaModelContext metaModelContext;
     
-//    /**
-//     * Collect any {@link ValidationFailure} to given validationFailures. 
-//     *  
-//     * @param validationFailures
-//     */
-//    @Override
-//    public void collectFailuresInto(@NonNull ValidationFailures validationFailures) {
-//        validationFailures.addAll(failures);
-//    }
-
-//    public void onFailure(
-//            @NonNull FacetHolder facetHolder, 
-//            @NonNull Identifier deficiencyOrigin,
-//            @NonNull String deficiencyMessageFormat, 
-//            Object... args) {
-//        
-//        DeficiencyFacet.appendTo(facetHolder, deficiencyOrigin, String.format(deficiencyMessageFormat, args));
-//        failures.add(deficiencyOrigin, deficiencyMessageFormat, args);
-//    }
-    
     protected IsisConfiguration getConfiguration() {
         return metaModelContext.getConfiguration();
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorForAmbiguousMixinAnnotations.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorForAmbiguousMixinAnnotations.java
index 1de1dd6..0578ac6 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorForAmbiguousMixinAnnotations.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorForAmbiguousMixinAnnotations.java
@@ -21,7 +21,6 @@ package org.apache.isis.core.metamodel.specloader.validator;
 import java.lang.annotation.Annotation;
 
 import org.apache.isis.core.metamodel.facets.FacetedMethod;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 
 import lombok.experimental.UtilityClass;
 
@@ -34,7 +33,7 @@ public class MetaModelValidatorForAmbiguousMixinAnnotations {
         
         final String annotationLiteral = "@" + annotationType.getSimpleName();
         
-        DeficiencyFacet.appendToWithFormat(
+        ValidationFailure.raiseFormatted(
                 holder, 
                 "Annotation %s on both method and type level is not allowed, "
                 + "it must be one or the other. Found with mixin: %s", 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorForConflictingOptionality.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorForConflictingOptionality.java
index f83211b..08b9841 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorForConflictingOptionality.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorForConflictingOptionality.java
@@ -20,7 +20,6 @@ package org.apache.isis.core.metamodel.specloader.validator;
 
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.IdentifiedHolder;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.mandatory.MandatoryFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.mandatory.MandatoryFacetDefault;
 
@@ -42,7 +41,7 @@ public class MetaModelValidatorForConflictingOptionality {
     private static Facet addFailure(final Facet facet, final String message) {
         if(facet != null) {
             val holder = (IdentifiedHolder) facet.getFacetHolder();
-            DeficiencyFacet.appendToWithFormat(
+            ValidationFailure.raiseFormatted(
                     holder, 
                     "%s : %s", 
                     message, 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorVisiting.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorVisiting.java
deleted file mode 100644
index 411aafa..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidatorVisiting.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.isis.core.metamodel.specloader.validator;
-
-import java.util.function.Predicate;
-
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.metamodel.specloader.SpecificationLoaderDefault;
-
-import lombok.NonNull;
-import lombok.val;
-
-public class MetaModelValidatorVisiting 
-extends MetaModelValidatorAbstract {
-
-    @Override
-    public String toString() {
-        return "MetaModelValidatorVisiting{" +
-                "visitor=" + visitor +
-                '}';
-    }
-
-    // -- INTERFACES
-    
-    @FunctionalInterface
-    public interface Visitor {
-        /**
-         * @return <tt>true</tt> continue visiting specs.
-         */
-        boolean visit(ObjectSpecification spec);
-    }
-    
-    public interface SummarizingVisitor extends Visitor {
-        void summarize();
-    }
-    
-    // -- IMPLEMENTATION
-
-    public static MetaModelValidatorVisiting of(
-            final @NonNull Visitor visitor,
-            final @NonNull Predicate<ObjectSpecification> includeIf) {
-        return new MetaModelValidatorVisiting(visitor, includeIf);
-    }
-
-
-    @NonNull private final Visitor visitor;
-    @NonNull private final Predicate<ObjectSpecification> includeIf;
-
-    private MetaModelValidatorVisiting(
-            final @NonNull Visitor visitor,
-            final @NonNull Predicate<ObjectSpecification> includeIf
-            ) {
-        this.visitor = visitor;
-        this.includeIf = includeIf;
-    }
-
-    @Override
-    public void validate() {
-        validateAll();
-        summarize();
-    }
-
-    private void validateAll() {
-
-        val specLoader = (SpecificationLoaderDefault)super.getMetaModelContext().getSpecificationLoader();
-        
-        val isActionExplicit = getConfiguration().getApplib().getAnnotation().getAction().isExplicit();
-        
-        specLoader.forEach(spec->{
-            
-            if(!isActionExplicit
-                    && spec.getBeanSort().isUnknown()) {
-                    return; // in support of @Action not being forced, we need to relax 
-            }
-            
-            if(!includeIf.test(spec)) {
-                return;
-            }
-            
-            visitor.visit(spec);
-        });
-    }
-
-    private void summarize() {
-        if(visitor instanceof SummarizingVisitor) {
-            ((SummarizingVisitor) visitor).summarize();
-        }
-    }
-
-}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidator.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelVisitingValidator.java
similarity index 73%
copy from core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidator.java
copy to core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelVisitingValidator.java
index a507865..2cff685 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidator.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelVisitingValidator.java
@@ -16,19 +16,22 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package org.apache.isis.core.metamodel.specloader.validator;
 
-public interface MetaModelValidator {
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
-    /**
-     * Collect any {@link ValidationFailure} to given validationFailures. 
-     *  
-     * @param validationFailures
-     */
-    //void collectFailuresInto(@NonNull ValidationFailures validationFailures);
-    
-    void validate();
+import lombok.NonNull;
+
+@FunctionalInterface
+public interface MetaModelVisitingValidator {
+
+//    /**
+//     * @return <tt>true</tt> continue visiting specs.
+//     */
+    void validate(@NonNull ObjectSpecification spec);
     
+    default void summarize() {
+        
+    }
     
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidator.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelVisitingValidatorAbstract.java
similarity index 55%
copy from core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidator.java
copy to core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelVisitingValidatorAbstract.java
index a507865..cf3793b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelValidator.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/MetaModelVisitingValidatorAbstract.java
@@ -16,19 +16,32 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package org.apache.isis.core.metamodel.specloader.validator;
 
-public interface MetaModelValidator {
+import lombok.val;
 
-    /**
-     * Collect any {@link ValidationFailure} to given validationFailures. 
-     *  
-     * @param validationFailures
-     */
-    //void collectFailuresInto(@NonNull ValidationFailures validationFailures);
-    
-    void validate();
-    
+public abstract class MetaModelVisitingValidatorAbstract 
+extends MetaModelValidatorAbstract
+implements MetaModelVisitingValidator {
+
+    @Override
+    public final void validate() {
+
+        val isActionExplicit = getConfiguration().getApplib().getAnnotation().getAction().isExplicit();
+        
+        super.getMetaModelContext().getSpecificationLoader()
+        .forEach(spec->{
+            
+            if(!isActionExplicit
+                    && spec.getBeanSort().isUnknown()) {
+                    return; // in support of @Action not being forced, we need to relax 
+            }
+            
+            validate(spec);
+        });
+        
+        summarize();
+        
+    }
     
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/ValidationFailure.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/ValidationFailure.java
index 30f6d0b..1d106a9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/ValidationFailure.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/validator/ValidationFailure.java
@@ -25,6 +25,8 @@ import static java.util.Comparator.naturalOrder;
 import static java.util.Comparator.nullsFirst;
 
 import org.apache.isis.applib.Identifier;
+import org.apache.isis.core.metamodel.facetapi.IdentifiedHolder;
+import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 
 import lombok.NonNull;
 import lombok.Value;
@@ -40,11 +42,47 @@ public final class ValidationFailure implements Comparable<ValidationFailure> {
     @NonNull private Identifier origin;
     @NonNull private String message;
 
+    // -- FACTORIES
+    
+    /**
+     * Collects a new ValidationFailure with given origin and message. 
+     */
+    public static void raise(
+            @NonNull SpecificationLoader specLoader,
+            @NonNull Identifier deficiencyOrigin, 
+            @NonNull String deficiencyMessage) {
+        
+        specLoader.addValidationFailure(ValidationFailure.of(deficiencyOrigin, deficiencyMessage));
+    }
+    
+    /**
+     * Collects a new ValidationFailure for given FacetHolder (that is the origin) using given message. 
+     */
+    public static void raise(
+            @NonNull IdentifiedHolder facetHolder, 
+            @NonNull String deficiencyMessage) {
+        raise(facetHolder.getSpecificationLoader(), facetHolder.getIdentifier(), deficiencyMessage);
+    }
+    
+    /**
+     * Collects a new ValidationFailure for given FacetHolder (that is the origin) using given message
+     * (assembled from format and args). 
+     */
+    public static void raiseFormatted(
+            @NonNull IdentifiedHolder facetHolder, 
+            @NonNull String messageFormat, 
+            final Object ...args) {
+        raise(facetHolder, String.format(messageFormat, args));
+    }
+    
+    
     private static final Comparator<ValidationFailure> comparator = Comparator
             .<ValidationFailure, String>comparing(failure->failure.getOrigin().getClassName(), nullsFirst(naturalOrder()))
             .<String>thenComparing(failure->failure.getOrigin().getMemberName(), nullsFirst(naturalOrder()))
             .thenComparing(ValidationFailure::getMessage);
 
+    // -- CONTRACT
+    
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
diff --git a/extensions/core/model-annotation/src/main/java/org/apache/isis/extensions/modelannotation/metamodel/facets/SupportingMethodValidatorRefinerFactory.java b/extensions/core/model-annotation/src/main/java/org/apache/isis/extensions/modelannotation/metamodel/facets/SupportingMethodValidatorRefinerFactory.java
index 9d2c961..1cfc34d 100644
--- a/extensions/core/model-annotation/src/main/java/org/apache/isis/extensions/modelannotation/metamodel/facets/SupportingMethodValidatorRefinerFactory.java
+++ b/extensions/core/model-annotation/src/main/java/org/apache/isis/extensions/modelannotation/metamodel/facets/SupportingMethodValidatorRefinerFactory.java
@@ -33,9 +33,9 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.ImperativeFacet;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 import org.apache.isis.extensions.modelannotation.applib.annotation.Model;
 
 /**
@@ -57,7 +57,7 @@ implements MetaModelRefiner {
     @Override
     public void refineProgrammingModel(ProgrammingModel programmingModel) {
 
-        programmingModel.addValidatorSkipManagedBeans(spec -> {
+        programmingModel.addVisitingValidatorSkipManagedBeans(spec -> {
 
             final Class<?> type = spec.getCorrespondingClass();
 
@@ -102,7 +102,7 @@ implements MetaModelRefiner {
 
                 String messageFormat = "%s#%s: has annotation @%s, is assumed to support "
                         + "a property, collection or action. Unmet constraint(s): %s";
-                DeficiencyFacet.appendToWithFormat(
+                ValidationFailure.raiseFormatted(
                         spec,
                         messageFormat,
                         spec.getIdentifier().getClassName(),
@@ -111,9 +111,7 @@ implements MetaModelRefiner {
                         unmetContraints.stream()
                         .collect(Collectors.joining("; ")));
             });
-
-
-            return true; // continue
+            
         });
 
     }
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/JdoProgrammingModel.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/JdoProgrammingModel.java
index 7dff1c1..ae18e67 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/JdoProgrammingModel.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/JdoProgrammingModel.java
@@ -23,7 +23,6 @@ import javax.jdo.annotations.IdentityType;
 import org.springframework.stereotype.Component;
 
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.collections.CollectionFacet;
 import org.apache.isis.core.metamodel.facets.object.ignore.datanucleus.RemoveDatanucleusPersistableTypesFacetFactory;
 import org.apache.isis.core.metamodel.facets.object.ignore.datanucleus.RemoveDnPrefixedMethodsFacetFactory;
@@ -32,6 +31,7 @@ import org.apache.isis.core.metamodel.facets.object.ignore.jdo.RemoveJdoPrefixed
 import org.apache.isis.core.metamodel.facets.object.parented.ParentedCollectionFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel.Marker;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 import org.apache.isis.persistence.jdo.metamodel.facets.object.datastoreidentity.JdoDatastoreIdentityAnnotationFacetFactory;
 import org.apache.isis.persistence.jdo.metamodel.facets.object.persistencecapable.JdoPersistenceCapableAnnotationFacetFactory;
 import org.apache.isis.persistence.jdo.metamodel.facets.object.query.JdoQueryAnnotationFacetFactory;
@@ -98,11 +98,11 @@ public class JdoProgrammingModel implements MetaModelRefiner {
 
     private void addValidatorToEnsureIdentityType(ProgrammingModel pm) {
 
-        pm.addValidatorSkipManagedBeans(objSpec -> {
+        pm.addVisitingValidatorSkipManagedBeans(objSpec -> {
 
             final JdoPersistenceCapableFacet jpcf = objSpec.getFacet(JdoPersistenceCapableFacet.class);
             if(jpcf == null) {
-                return true;
+                return;
             }
             final IdentityType identityType = jpcf.getIdentityType();
             if(identityType == IdentityType.APPLICATION) {
@@ -118,28 +118,26 @@ public class JdoProgrammingModel implements MetaModelRefiner {
             } else {
                 // in fact, at the time of writing there are no others, so this is theoretical in case there is
                 // a future change to the JDO spec
-                DeficiencyFacet.appendToWithFormat(
+                ValidationFailure.raiseFormatted(
                         objSpec,
                         "%s: is annotated with @PersistenceCapable but with an unrecognized identityType (%s)",
                         objSpec.getFullIdentifier(),
                         identityType);
             }
 
-            return true;
         }, Marker.JDO);
 
     }
 
     private void addValidatorToCheckForUnsupportedAnnotations(ProgrammingModel pm) {
 
-        pm.addValidatorSkipManagedBeans(objSpec -> {
+        pm.addVisitingValidatorSkipManagedBeans(objSpec -> {
             if (objSpec.containsNonFallbackFacet(ParentedCollectionFacet.class) && !objSpec.containsNonFallbackFacet(CollectionFacet.class)) {
-                DeficiencyFacet.appendToWithFormat(
+                ValidationFailure.raiseFormatted(
                         objSpec,
                         "%s: JDO/DataNucleus object store currently does not supported Aggregated or EmbeddedOnly annotations",
                         objSpec.getFullIdentifier());
             }
-            return true;
         }, Marker.JDO);
 
     }
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/JdoQueryAnnotationFacetFactory.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/JdoQueryAnnotationFacetFactory.java
index 56144b4..befca31 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/JdoQueryAnnotationFacetFactory.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/JdoQueryAnnotationFacetFactory.java
@@ -74,13 +74,13 @@ implements MetaModelRefiner {
         val isValidateFromClause = 
                 getConfiguration().getCore().getMetaModel().getValidator().getJdoql().isFromClause();
         if (isValidateFromClause) {
-            programmingModel.addValidatorSkipManagedBeans(new VisitorForFromClause(this));
+            programmingModel.addValidator(new VisitorForFromClause());
         }
 
         val isValidateVariablesClause = 
                 getConfiguration().getCore().getMetaModel().getValidator().getJdoql().isVariablesClause();
         if (isValidateVariablesClause) {
-            programmingModel.addValidatorSkipManagedBeans(new VisitorForVariablesClause(this));
+            programmingModel.addValidator(new VisitorForVariablesClause());
         }
     }
 
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForClauseAbstract.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForClauseAbstract.java
index 324e282..3dadcf3 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForClauseAbstract.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForClauseAbstract.java
@@ -23,34 +23,31 @@ import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.context._Context;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
+import org.apache.isis.core.metamodel.specloader.validator.MetaModelVisitingValidatorAbstract;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 import org.apache.isis.persistence.jdo.provider.metamodel.facets.object.query.JdoQueryFacet;
 
 import lombok.val;
 
-abstract class VisitorForClauseAbstract implements MetaModelValidatorVisiting.Visitor {
+abstract class VisitorForClauseAbstract 
+extends MetaModelVisitingValidatorAbstract {
 
-    private final JdoQueryAnnotationFacetFactory facetFactory;
     final String clause;
 
     VisitorForClauseAbstract(
-            final JdoQueryAnnotationFacetFactory facetFactory,
             final String clause) {
         
-        this.facetFactory = facetFactory;
         this.clause = clause;
     }
 
     @Override
-    public boolean visit(final ObjectSpecification objectSpec) {
-        validate(objectSpec);
-        return true;
-    }
-
-    private void validate(final ObjectSpecification objectSpec) {
+    public void validate(final ObjectSpecification objectSpec) {
+        
+        if(objectSpec.isManagedBean()) {
+            return;
+        }
         
         val jdoQueryFacet = objectSpec.getFacet(JdoQueryFacet.class);
         if(jdoQueryFacet == null) {
@@ -82,8 +79,8 @@ abstract class VisitorForClauseAbstract implements MetaModelValidatorVisiting.Vi
             
         if(fromSpecResult.isFailure() 
                 || !fromSpecResult.getValue().isPresent()) {
-            DeficiencyFacet.appendTo(
-                    objectSpec,
+            ValidationFailure.raise(
+                    objectSpec.getSpecificationLoader(),
                     Identifier.classIdentifier(LogicalType.fqcn(cls)),
                     String.format(
                             "%s: error in JDOQL query, class name for '%s' clause not recognized (JDOQL : %s)",
@@ -106,7 +103,7 @@ abstract class VisitorForClauseAbstract implements MetaModelValidatorVisiting.Vi
 
 
     SpecificationLoader getSpecificationLoader() {
-        return facetFactory.getSpecificationLoader();
+        return super.getMetaModelContext().getSpecificationLoader();
     }
 
 }
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForFromClause.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForFromClause.java
index 38a6582..8a25141 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForFromClause.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForFromClause.java
@@ -24,17 +24,16 @@ import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.internal.context._Context;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.spec.Hierarchical;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 
 import lombok.val;
 
 class VisitorForFromClause extends VisitorForClauseAbstract {
 
-    VisitorForFromClause(
-            final JdoQueryAnnotationFacetFactory specificationLoader) {
-        super(specificationLoader, "FROM");
+    VisitorForFromClause() {
+        super("FROM");
     }
 
     @Override
@@ -59,8 +58,8 @@ class VisitorForFromClause extends VisitorForClauseAbstract {
                 
         if(fromSpecResult.isFailure() 
                 || !fromSpecResult.getValue().isPresent()) {
-            DeficiencyFacet.appendTo(
-                    objectSpec,
+            ValidationFailure.raise(
+                    objectSpec.getSpecificationLoader(),
                     Identifier.classIdentifier(LogicalType.fqcn(cls)),
                     String.format(
                             "%s: error in JDOQL query, "
@@ -77,8 +76,8 @@ class VisitorForFromClause extends VisitorForClauseAbstract {
         if(subclasses.contains(objectSpec)) {
             return;
         }
-        DeficiencyFacet.appendTo(
-                objectSpec,
+        ValidationFailure.raise(
+                objectSpec.getSpecificationLoader(),
                 Identifier.classIdentifier(LogicalType.fqcn(cls)),
                 String.format(
                         "%s: error in JDOQL query, class name after '%s' "
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForVariablesClause.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForVariablesClause.java
index ba19232..03d4200 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForVariablesClause.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForVariablesClause.java
@@ -20,17 +20,17 @@ package org.apache.isis.persistence.jdo.metamodel.facets.object.query;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.id.LogicalType;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.specimpl.IntrospectionState;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 import org.apache.isis.persistence.jdo.provider.metamodel.facets.object.persistencecapable.JdoPersistenceCapableFacet;
 
 import lombok.val;
 
 class VisitorForVariablesClause extends VisitorForClauseAbstract {
 
-    VisitorForVariablesClause(final JdoQueryAnnotationFacetFactory facetFactory) {
-        super(facetFactory, "VARIABLES");
+    VisitorForVariablesClause() {
+        super("VARIABLES");
     }
 
     @Override
@@ -55,8 +55,8 @@ class VisitorForVariablesClause extends VisitorForClauseAbstract {
                 objectSpecification.getFacet(JdoPersistenceCapableFacet.class);
 
         if(persistenceCapableFacet == null) {
-            DeficiencyFacet.appendTo(
-                    objectSpec,
+            ValidationFailure.raise(
+                    objectSpec.getSpecificationLoader(),
                     Identifier.classIdentifier(LogicalType.fqcn(cls)),
                     String.format(
                             "%s: error in JDOQL query, class name for '%s' "
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/JdoVersionAnnotationFacetFactory.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/JdoVersionAnnotationFacetFactory.java
index 9848d32..501b4b2 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/JdoVersionAnnotationFacetFactory.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/JdoVersionAnnotationFacetFactory.java
@@ -27,11 +27,9 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.Annotations;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting.Visitor;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 import org.apache.isis.persistence.jdo.provider.entities.JdoFacetContext;
 
 import lombok.Setter;
@@ -65,44 +63,30 @@ implements MetaModelRefiner {
 
     @Override
     public void refineProgrammingModel(ProgrammingModel programmingModel) {
-        programmingModel.addValidatorSkipManagedBeans(newValidatorVisitor());
-    }
-
-    Visitor newValidatorVisitor() {
-        return new MetaModelValidatorVisiting.Visitor() {
+        programmingModel.addVisitingValidatorSkipManagedBeans(spec->{
 
-            @Override
-            public boolean visit(ObjectSpecification objectSpec) {
-                validate(objectSpec);
-                return true;
+            if(!declaresVersionAnnotation(spec)) {
+                return;
             }
 
-            private void validate(ObjectSpecification objectSpec) {
-                if(!declaresVersionAnnotation(objectSpec)) {
+            ObjectSpecification superclassSpec = spec.superclass();
+            while(superclassSpec != null) {
+                if(declaresVersionAnnotation(superclassSpec)) {
+                    ValidationFailure.raiseFormatted(
+                            spec,
+                            "%s: cannot have @Version annotated on this subclass and any of its supertypes; superclass: %s",
+                            spec.getFullIdentifier(),
+                            superclassSpec.getFullIdentifier() );
                     return;
                 }
-
-                ObjectSpecification superclassSpec = objectSpec.superclass();
-                while(superclassSpec != null) {
-                    if(declaresVersionAnnotation(superclassSpec)) {
-                        DeficiencyFacet.appendToWithFormat(
-                                objectSpec,
-                                "%s: cannot have @Version annotated on this subclass and any of its supertypes; superclass: %s",
-                                objectSpec.getFullIdentifier(),
-                                superclassSpec.getFullIdentifier() );
-                        return;
-                    }
-                    superclassSpec = superclassSpec.superclass();
-                }
+                superclassSpec = superclassSpec.superclass();
             }
-
-            private boolean declaresVersionAnnotation(ObjectSpecification objectSpec) {
-                return Annotations.getDeclaredAnnotation(objectSpec.getCorrespondingClass(), Version.class)!=null;
-            }
-        };
+        });
     }
 
-
+    private static boolean declaresVersionAnnotation(ObjectSpecification spec) {
+        return Annotations.getDeclaredAnnotation(spec.getCorrespondingClass(), Version.class)!=null;
+    }
 
 
 }
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/BigDecimalDerivedFromJdoColumnAnnotationFacetFactory.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/BigDecimalDerivedFromJdoColumnAnnotationFacetFactory.java
index 843e877..da918ca 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/BigDecimalDerivedFromJdoColumnAnnotationFacetFactory.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/BigDecimalDerivedFromJdoColumnAnnotationFacetFactory.java
@@ -27,16 +27,13 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.FacetedMethod;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.properties.bigdecimal.javaxvaldigits.BigDecimalFacetOnPropertyFromJavaxValidationDigitsAnnotation;
 import org.apache.isis.core.metamodel.facets.value.bigdecimal.BigDecimalValueFacet;
 import org.apache.isis.core.metamodel.facets.value.bigdecimal.BigDecimalValueSemanticsProvider;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting.Visitor;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 import org.apache.isis.persistence.jdo.provider.metamodel.facets.object.persistencecapable.JdoPersistenceCapableFacet;
 import org.apache.isis.persistence.jdo.provider.metamodel.facets.prop.notpersistent.JdoNotPersistentFacet;
 
@@ -103,72 +100,64 @@ implements MetaModelRefiner {
 
     @Override
     public void refineProgrammingModel(ProgrammingModel programmingModel) {
-        programmingModel.addValidatorSkipManagedBeans(newValidatorVisitor());
-    }
-
-    private Visitor newValidatorVisitor() {
-        return new MetaModelValidatorVisiting.Visitor() {
+        programmingModel.addVisitingValidatorSkipManagedBeans(spec->{
 
-            @Override
-            public boolean visit(ObjectSpecification objectSpec) {
-                validate(objectSpec);
-                return true;
+            // only consider persistent entities
+            final JdoPersistenceCapableFacet pcFacet = spec.getFacet(JdoPersistenceCapableFacet.class);
+            if(pcFacet==null || pcFacet.getIdentityType() == IdentityType.NONDURABLE) {
+                return;
             }
 
-            private void validate(ObjectSpecification objectSpec) {
-
-                // only consider persistent entities
-                final JdoPersistenceCapableFacet pcFacet = objectSpec.getFacet(JdoPersistenceCapableFacet.class);
-                if(pcFacet==null || pcFacet.getIdentityType() == IdentityType.NONDURABLE) {
-                    return;
-                }
+            spec.streamProperties(MixedIn.EXCLUDED)
+            // skip checks if annotated with JDO @NotPersistent
+            .filter(association->!association.containsNonFallbackFacet(JdoNotPersistentFacet.class))
+            .forEach(association->{
+                validateBigDecimalValueFacet(association);
+            });
+            
+        });
+    }
+    
+    private static void validateBigDecimalValueFacet(ObjectAssociation association) {
+        BigDecimalValueFacet facet = association.getFacet(BigDecimalValueFacet.class);
+        if(facet == null) {
+            return;
+        }
 
-                objectSpec.streamProperties(MixedIn.EXCLUDED)
-                // skip checks if annotated with JDO @NotPersistent
-                .filter(association->!association.containsNonFallbackFacet(JdoNotPersistentFacet.class))
-                .forEach(association->{
-                    validateBigDecimalValueFacet(association);
-                });
+        BigDecimalValueFacet underlying = (BigDecimalValueFacet) facet.getUnderlyingFacet();
+        if(underlying == null) {
+            return;
+        }
 
-            }
+        if(facet instanceof BigDecimalFacetDerivedFromJdoColumn) {
 
-            private void validateBigDecimalValueFacet(ObjectAssociation association) {
-                BigDecimalValueFacet facet = association.getFacet(BigDecimalValueFacet.class);
-                if(facet == null) {
-                    return;
-                }
+            if(underlying instanceof BigDecimalFacetOnPropertyFromJavaxValidationDigitsAnnotation) {
 
-                BigDecimalValueFacet underlying = (BigDecimalValueFacet) facet.getUnderlyingFacet();
-                if(underlying == null) {
-                    return;
+                if(notNullButNotEqual(facet.getPrecision(), underlying.getPrecision())) {
+                    ValidationFailure.raise(
+                            association,
+                            String.format("%s: @javax.jdo.annotations.Column(length=...) "
+                                    + "different from @javax.validation.constraint.Digits(...); "
+                                    + "should equal the sum of its integer and fraction attributes",
+                                    association.getIdentifier().toString())
+                            );
                 }
 
-                if(facet instanceof BigDecimalFacetDerivedFromJdoColumn) {
-
-                    if(underlying instanceof BigDecimalFacetOnPropertyFromJavaxValidationDigitsAnnotation) {
-
-                        if(notNullButNotEqual(facet.getPrecision(), underlying.getPrecision())) {
-                            DeficiencyFacet.appendToWithFormat(
-                                    association,
-                                    "%s: @javax.jdo.annotations.Column(length=...) different from @javax.validation.constraint.Digits(...); should equal the sum of its integer and fraction attributes",
-                                    association.getIdentifier().toString());
-                        }
-
-                        if(notNullButNotEqual(facet.getScale(), underlying.getScale())) {
-                            DeficiencyFacet.appendToWithFormat(
-                                    association,
-                                    "%s: @javax.jdo.annotations.Column(scale=...) different from @javax.validation.constraint.Digits(fraction=...)",
-                                    association.getIdentifier().toString());
-                        }
-                    }
+                if(notNullButNotEqual(facet.getScale(), underlying.getScale())) {
+                    ValidationFailure.raise(
+                            association,
+                            String.format("%s: @javax.jdo.annotations.Column(scale=...) "
+                                    + "different from @javax.validation.constraint.Digits(fraction=...)",
+                                    association.getIdentifier().toString())
+                            );
                 }
             }
-
-            private boolean notNullButNotEqual(Integer x, Integer y) {
-                return x != null && y != null && !x.equals(y);
-            }
-        };
+        }
     }
 
+    private static boolean notNullButNotEqual(Integer x, Integer y) {
+        return x != null && y != null && !x.equals(y);
+    }
+    
 
 }
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/MandatoryFromJdoColumnAnnotationFacetFactory.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/MandatoryFromJdoColumnAnnotationFacetFactory.java
index befdcaf..895a832 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/MandatoryFromJdoColumnAnnotationFacetFactory.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/MandatoryFromJdoColumnAnnotationFacetFactory.java
@@ -30,16 +30,13 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.FacetedMethod;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.mandatory.MandatoryFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.mandatory.MandatoryFacetDefault;
 import org.apache.isis.core.metamodel.facets.properties.property.mandatory.MandatoryFacetForPropertyAnnotation;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting.Visitor;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 import org.apache.isis.persistence.jdo.metamodel.facets.prop.primarykey.OptionalFacetDerivedFromJdoPrimaryKeyAnnotation;
 import org.apache.isis.persistence.jdo.provider.entities.JdoFacetContext;
 import org.apache.isis.persistence.jdo.provider.metamodel.facets.object.persistencecapable.JdoPersistenceCapableFacet;
@@ -122,83 +119,71 @@ implements MetaModelRefiner {
 
     @Override
     public void refineProgrammingModel(ProgrammingModel programmingModel) {
-        programmingModel.addValidatorSkipManagedBeans(newValidatorVisitor());
-    }
+        programmingModel.addVisitingValidatorSkipManagedBeans(objectSpec->{
+            
+            final JdoPersistenceCapableFacet pcFacet = objectSpec.getFacet(JdoPersistenceCapableFacet.class);
+            if(pcFacet==null || pcFacet.getIdentityType() == IdentityType.NONDURABLE) {
+                return;
+            }
 
-    private Visitor newValidatorVisitor() {
-        return new MetaModelValidatorVisiting.Visitor() {
+            final Stream<ObjectAssociation> associations = objectSpec
+                    .streamAssociations(MixedIn.EXCLUDED)
+                    .filter(ObjectAssociation.Predicates.PROPERTIES);
 
-            @Override
-            public boolean visit(ObjectSpecification objectSpec) {
-                validate(objectSpec);
-                return true;
-            }
+            associations
+            // skip checks if annotated with JDO @NotPersistent
+            .filter(association->!association.containsNonFallbackFacet(JdoNotPersistentFacet.class))
+            .forEach(association->validateMandatoryFacet(association));
+            
+        });
+    }
+    
+    private static void validateMandatoryFacet(ObjectAssociation association) {
+        MandatoryFacet facet = association.getFacet(MandatoryFacet.class);
 
-            private void validate(ObjectSpecification objectSpec) {
+        MandatoryFacet underlying = (MandatoryFacet) facet.getUnderlyingFacet();
+        if(underlying == null) {
+            return;
+        }
 
-                final JdoPersistenceCapableFacet pcFacet = objectSpec.getFacet(JdoPersistenceCapableFacet.class);
-                if(pcFacet==null || pcFacet.getIdentityType() == IdentityType.NONDURABLE) {
-                    return;
-                }
+        if(facet instanceof MandatoryFacetDerivedFromJdoColumn) {
 
-                final Stream<ObjectAssociation> associations = objectSpec
-                        .streamAssociations(MixedIn.EXCLUDED)
-                        .filter(ObjectAssociation.Predicates.PROPERTIES);
+            if(underlying.isInvertedSemantics() == facet.isInvertedSemantics()) {
+                return;
+            }
 
-                associations
-                // skip checks if annotated with JDO @NotPersistent
-                .filter(association->!association.containsNonFallbackFacet(JdoNotPersistentFacet.class))
-                .forEach(association->validateMandatoryFacet(association));
+            if(underlying.isInvertedSemantics()) {
+                // ie @Optional
+                ValidationFailure.raiseFormatted(
+                        association,
+                        "%s: incompatible usage of Isis' @Optional annotation and @javax.jdo.annotations.Column; use just @javax.jdo.annotations.Column(allowsNull=\"...\")",
+                        association.getIdentifier().getFullIdentityString());
+            } else {
+                ValidationFailure.raiseFormatted(
+                        association,
+                        "%s: incompatible Isis' default of required/optional properties vs JDO; add @javax.jdo.annotations.Column(allowsNull=\"...\")",
+                        association.getIdentifier().getFullIdentityString());
             }
+        }
+
+        if(facet instanceof MandatoryFacetInferredFromAbsenceOfJdoColumn) {
 
-            private void validateMandatoryFacet(ObjectAssociation association) {
-                MandatoryFacet facet = association.getFacet(MandatoryFacet.class);
-
-                MandatoryFacet underlying = (MandatoryFacet) facet.getUnderlyingFacet();
-                if(underlying == null) {
-                    return;
-                }
-
-                if(facet instanceof MandatoryFacetDerivedFromJdoColumn) {
-
-                    if(underlying.isInvertedSemantics() == facet.isInvertedSemantics()) {
-                        return;
-                    }
-
-                    if(underlying.isInvertedSemantics()) {
-                        // ie @Optional
-                        DeficiencyFacet.appendToWithFormat(
-                                association,
-                                "%s: incompatible usage of Isis' @Optional annotation and @javax.jdo.annotations.Column; use just @javax.jdo.annotations.Column(allowsNull=\"...\")",
-                                association.getIdentifier().getFullIdentityString());
-                    } else {
-                        DeficiencyFacet.appendToWithFormat(
-                                association,
-                                "%s: incompatible Isis' default of required/optional properties vs JDO; add @javax.jdo.annotations.Column(allowsNull=\"...\")",
-                                association.getIdentifier().getFullIdentityString());
-                    }
-                }
-
-                if(facet instanceof MandatoryFacetInferredFromAbsenceOfJdoColumn) {
-
-                    if(underlying.isInvertedSemantics() == facet.isInvertedSemantics()) {
-                        return;
-                    }
-                    if(underlying.isInvertedSemantics()) {
-                        // ie @Optional
-                        DeficiencyFacet.appendToWithFormat(
-                                association,
-                                "%s: incompatible usage of Isis' @Optional annotation and @javax.jdo.annotations.Column; use just @javax.jdo.annotations.Column(allowsNull=\"...\")",
-                                association.getIdentifier().getFullIdentityString());
-                    } else {
-                        DeficiencyFacet.appendToWithFormat(
-                                association,
-                                "%s: incompatible default handling of required/optional properties between Isis and JDO; add @javax.jdo.annotations.Column(allowsNull=\"...\")",
-                                association.getIdentifier().getFullIdentityString());
-                    }
-                }
+            if(underlying.isInvertedSemantics() == facet.isInvertedSemantics()) {
+                return;
+            }
+            if(underlying.isInvertedSemantics()) {
+                // ie @Optional
+                ValidationFailure.raiseFormatted(
+                        association,
+                        "%s: incompatible usage of Isis' @Optional annotation and @javax.jdo.annotations.Column; use just @javax.jdo.annotations.Column(allowsNull=\"...\")",
+                        association.getIdentifier().getFullIdentityString());
+            } else {
+                ValidationFailure.raiseFormatted(
+                        association,
+                        "%s: incompatible default handling of required/optional properties between Isis and JDO; add @javax.jdo.annotations.Column(allowsNull=\"...\")",
+                        association.getIdentifier().getFullIdentityString());
             }
-        };
+        }
     }
 
 }
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/MaxLengthDerivedFromJdoColumnAnnotationFacetFactory.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/MaxLengthDerivedFromJdoColumnAnnotationFacetFactory.java
index 96b6667..535a411 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/MaxLengthDerivedFromJdoColumnAnnotationFacetFactory.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/prop/column/MaxLengthDerivedFromJdoColumnAnnotationFacetFactory.java
@@ -29,15 +29,12 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.facets.FacetedMethod;
-import org.apache.isis.core.metamodel.facets.all.deficiencies.DeficiencyFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.maxlen.MaxLengthFacet;
 import org.apache.isis.core.metamodel.facets.properties.property.maxlength.MaxLengthFacetForPropertyAnnotation;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting.Visitor;
+import org.apache.isis.core.metamodel.specloader.validator.ValidationFailure;
 import org.apache.isis.persistence.jdo.provider.entities.JdoFacetContext;
 import org.apache.isis.persistence.jdo.provider.metamodel.facets.object.persistencecapable.JdoPersistenceCapableFacet;
 import org.apache.isis.persistence.jdo.provider.metamodel.facets.prop.notpersistent.JdoNotPersistentFacet;
@@ -94,59 +91,41 @@ implements MetaModelRefiner {
 
     @Override
     public void refineProgrammingModel(ProgrammingModel programmingModel) {
-        programmingModel.addValidatorSkipManagedBeans(newValidatorVisitor());
-    }
-
-    private Visitor newValidatorVisitor() {
-        return new MetaModelValidatorVisiting.Visitor() {
-
-            @Override
-            public boolean visit(ObjectSpecification objectSpec) {
-                validate(objectSpec);
-                return true;
+        programmingModel.addVisitingValidatorSkipManagedBeans(objectSpec->{
+            final JdoPersistenceCapableFacet pcFacet = objectSpec.getFacet(JdoPersistenceCapableFacet.class);
+            if(pcFacet==null || pcFacet.getIdentityType() == IdentityType.NONDURABLE) {
+                return;
             }
 
-            private void validate(ObjectSpecification objectSpec) {
+            final Stream<ObjectAssociation> associations = objectSpec
+                    .streamAssociations(MixedIn.EXCLUDED)
+                    .filter(ObjectAssociation.Predicates.PROPERTIES);
 
-                final JdoPersistenceCapableFacet pcFacet = objectSpec.getFacet(JdoPersistenceCapableFacet.class);
-                if(pcFacet==null || pcFacet.getIdentityType() == IdentityType.NONDURABLE) {
+            associations.forEach(association->{
+                // skip checks if annotated with JDO @NotPersistent
+                if(association.containsNonFallbackFacet(JdoNotPersistentFacet.class)) {
                     return;
                 }
 
-                final Stream<ObjectAssociation> associations = objectSpec
-                        .streamAssociations(MixedIn.EXCLUDED)
-                        .filter(ObjectAssociation.Predicates.PROPERTIES);
-
-                associations.forEach(association->{
-                    // skip checks if annotated with JDO @NotPersistent
-                    if(association.containsNonFallbackFacet(JdoNotPersistentFacet.class)) {
-                        return;
-                    }
-
-                    final MaxLengthFacet facet = association.getFacet(MaxLengthFacet.class);
-                    final MaxLengthFacet underlying = (MaxLengthFacet) facet.getUnderlyingFacet();
-                    if(underlying == null) {
-                        return;
-                    }
+                final MaxLengthFacet facet = association.getFacet(MaxLengthFacet.class);
+                final MaxLengthFacet underlying = (MaxLengthFacet) facet.getUnderlyingFacet();
+                if(underlying == null) {
+                    return;
+                }
 
-                    if(facet instanceof MaxLengthFacetDerivedFromJdoColumn 
-                            && underlying instanceof MaxLengthFacetForPropertyAnnotation) {
-                        if(facet.value() != underlying.value()) {
-                            DeficiencyFacet.appendToWithFormat(
-                                    association,
-                                    "%s: inconsistent lengths specified in Isis' @Property(maxLength=...) "
-                                    + "and @javax.jdo.annotations.Column(length=...); "
-                                    + "use just @javax.jdo.annotations.Column(length=...)",
-                                    association.getIdentifier().toString());
-                        }
+                if(facet instanceof MaxLengthFacetDerivedFromJdoColumn 
+                        && underlying instanceof MaxLengthFacetForPropertyAnnotation) {
+                    if(facet.value() != underlying.value()) {
+                        ValidationFailure.raiseFormatted(
+                                association,
+                                "%s: inconsistent lengths specified in Isis' @Property(maxLength=...) "
+                                + "and @javax.jdo.annotations.Column(length=...); "
+                                + "use just @javax.jdo.annotations.Column(length=...)",
+                                association.getIdentifier().toString());
                     }
-                });
-
-
-            }
-        };
+                }
+            });
+        });
     }
 
-
-
 }
diff --git a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/JdoVersionAnnotationFacetFactoryTest_refineMetaModel.java b/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/JdoVersionAnnotationFacetFactoryTest_refineMetaModel.java
index efb6099..a69509d 100644
--- a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/JdoVersionAnnotationFacetFactoryTest_refineMetaModel.java
+++ b/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/JdoVersionAnnotationFacetFactoryTest_refineMetaModel.java
@@ -20,6 +20,7 @@ package org.apache.isis.persistence.jdo.metamodel.facets.object.version;
 
 import javax.jdo.annotations.Version;
 
+import org.hamcrest.CoreMatchers;
 import org.jmock.Expectations;
 import org.jmock.Sequence;
 import org.junit.Before;
@@ -31,6 +32,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.services.inject.ServiceInjector;
+import org.apache.isis.commons.internal.reflection._Reflect;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2.Mode;
@@ -39,7 +41,6 @@ import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModelAbstract;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModelInitFilterDefault;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting.Visitor;
 import org.apache.isis.persistence.jdo.metamodel.testing.AbstractFacetFactoryTest;
 
 import lombok.val;
@@ -54,7 +55,6 @@ public class JdoVersionAnnotationFacetFactoryTest_refineMetaModel {
     private ObjectSpecification mockGrandParentType;
     private ServiceInjector mockServicesInjector;
 
-    private Visitor newValidatorVisitor;
     private MetaModelContext metaModelContext;
 
     private Sequence sequence;
@@ -64,23 +64,30 @@ public class JdoVersionAnnotationFacetFactoryTest_refineMetaModel {
         mockChildType = context.mock(ObjectSpecification.class, "mockChildtype");
         mockParentType = context.mock(ObjectSpecification.class, "mockParenttype");
         mockGrandParentType = context.mock(ObjectSpecification.class, "mockGrandParenttype");
+        mockServicesInjector = context.mock(ServiceInjector.class, "mockServicesInjector");
 
         val configuration = new IsisConfiguration(null);
 
+        val facetFactory = new JdoVersionAnnotationFacetFactory();
+        facetFactory.setJdoFacetContext(AbstractFacetFactoryTest.jdoFacetContextForTesting());
+        
         val programmingModel = new ProgrammingModelAbstract(mockServicesInjector) {};
-        programmingModel.init(new ProgrammingModelInitFilterDefault(), metaModelContext);
         
         metaModelContext = MetaModelContext_forTesting.builder()
                 .configuration(configuration)
                 .programmingModel(programmingModel)
                 .build();
+        
+        _Reflect.setFieldOn(
+                ProgrammingModelAbstract.class.getDeclaredField("serviceInjector"), 
+                programmingModel, 
+                metaModelContext.getServiceInjector());
+        
+        facetFactory.refineProgrammingModel(programmingModel);
+        programmingModel.init(new ProgrammingModelInitFilterDefault(), metaModelContext);
 
         sequence = context.sequence("inorder");
         
-        val facetFactory = new JdoVersionAnnotationFacetFactory();
-        facetFactory.setJdoFacetContext(AbstractFacetFactoryTest.jdoFacetContextForTesting());
-        
-        newValidatorVisitor = facetFactory.newValidatorVisitor();
     }
 
     @Test
@@ -90,12 +97,12 @@ public class JdoVersionAnnotationFacetFactoryTest_refineMetaModel {
 
         context.checking(new Expectations() {
             {
-                oneOf(mockChildType).getCorrespondingClass();
+                allowing(mockChildType).getCorrespondingClass();
                 will(returnValue(Child.class));
             }
         });
 
-        newValidatorVisitor.visit(mockChildType);
+        validate(mockChildType);
         
         val failures = metaModelContext.getSpecificationLoader().getValidationResult();
         assertThat(failures.getNumberOfFailures(), is(0));
@@ -109,17 +116,18 @@ public class JdoVersionAnnotationFacetFactoryTest_refineMetaModel {
 
         context.checking(new Expectations() {
             {
-                oneOf(mockChildType).getCorrespondingClass();
+                
+                allowing(mockChildType).getCorrespondingClass();
                 inSequence(sequence);
                 will(returnValue(Child.class));
 
-                oneOf(mockChildType).superclass();
+                allowing(mockChildType).superclass();
                 inSequence(sequence);
                 will(returnValue(null));
             }
         });
 
-        newValidatorVisitor.visit(mockChildType);
+        validate(mockChildType);
 
         val failures = metaModelContext.getSpecificationLoader().getValidationResult();
         assertThat(failures.getNumberOfFailures(), is(0));
@@ -135,32 +143,33 @@ public class JdoVersionAnnotationFacetFactoryTest_refineMetaModel {
 
         context.checking(new Expectations() {
             {
-                oneOf(mockChildType).getCorrespondingClass();
+                
+                allowing(mockChildType).getCorrespondingClass();
                 inSequence(sequence);
                 will(returnValue(Child.class));
 
-                oneOf(mockChildType).superclass();
+                allowing(mockChildType).superclass();
                 inSequence(sequence);
                 will(returnValue(mockParentType));
 
-                oneOf(mockParentType).getCorrespondingClass();
+                allowing(mockParentType).getCorrespondingClass();
                 inSequence(sequence);
                 will(returnValue(Parent.class));
 
-                oneOf(mockParentType).superclass();
+                allowing(mockParentType).superclass();
                 inSequence(sequence);
                 will(returnValue(null));
             }
         });
 
-        newValidatorVisitor.visit(mockChildType);
+        validate(mockChildType);
 
         val failures = metaModelContext.getSpecificationLoader().getValidationResult();
         assertThat(failures.getNumberOfFailures(), is(0));
     }
 
 
-    @Test
+    @Test 
     public void whenHasFacetWithParentTypeHasFacet() {
 
         @Version
@@ -206,12 +215,15 @@ public class JdoVersionAnnotationFacetFactoryTest_refineMetaModel {
             }
         });
 
-        newValidatorVisitor.visit(mockChildType);
+        validate(mockChildType);
 
+        //((SpecificationLoaderDefault)metaModelContext.getSpecificationLoader()).invalidateValidationResult();
+        
         val failures = metaModelContext.getSpecificationLoader().getValidationResult();
         
         assertThat(failures.getNumberOfFailures(), is(1));
-        assertThat(failures.getMessages().iterator().next(), is("mockChildType: cannot have @Version annotated on this subclass and any of its supertypes; superclass: mockParentType"));
+        assertThat(failures.getMessages().iterator().next(), 
+                CoreMatchers.containsString("cannot have @Version annotated on this subclass and any of its supertypes; superclass: "));
     }
 
 
@@ -272,12 +284,17 @@ public class JdoVersionAnnotationFacetFactoryTest_refineMetaModel {
             }
         });
 
-        newValidatorVisitor.visit(mockChildType);
+        validate(mockChildType);
 
         val failures = metaModelContext.getSpecificationLoader().getValidationResult();
         
         assertThat(failures.getNumberOfFailures(), is(1));
-        assertThat(failures.getMessages().iterator().next(), is("mockChildType: cannot have @Version annotated on this subclass and any of its supertypes; superclass: mockGrandParentType"));
+        assertThat(failures.getMessages().iterator().next(), 
+                CoreMatchers.containsString("cannot have @Version annotated on this subclass and any of its supertypes; superclass: "));
+    }
+
+    private void validate(ObjectSpecification spec) {
+        metaModelContext.getSpecificationLoader().loadSpecification(spec.getCorrespondingClass());
     }
 
 }