You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by ah...@apache.org on 2025/03/11 08:10:09 UTC

(causeway) branch main updated: CAUSEWAY-3859: flattens ManagedObjectOther into a record

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

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


The following commit(s) were added to refs/heads/main by this push:
     new a38986a7b74 CAUSEWAY-3859: flattens ManagedObjectOther into a record
a38986a7b74 is described below

commit a38986a7b74e3ce5f3c819f70950a7f956afaa65
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Mar 11 09:10:03 2025 +0100

    CAUSEWAY-3859: flattens ManagedObjectOther into a record
---
 .../_testing/MetaModelContext_forTesting.java      |   2 +-
 .../causeway/core/metamodel/commons/UtilStr.java   |   8 +-
 .../context/MetaModelContext_usingSpring.java      |   2 +-
 .../core/metamodel/execution/PropertyModifier.java |   2 +-
 .../actions/action/invocation/IdentifierUtil.java  |   2 +-
 .../facets/collections/CollectionFacet.java        |   2 +-
 .../choices/ChoicesFacetFromBoundedAbstract.java   |   2 +-
 .../facets/object/grid/GridFacetDefault.java       |   4 +-
 .../impl/ObjectValidPropertiesFacetImpl.java       |   2 +-
 .../ident/CssClassFacetFromProjectionFacet.java    |  10 +-
 .../ident/IconFacetFromProjectionFacet.java        |   2 +-
 .../title/methods/TitleFacetViaTitleMethod.java    |   2 +-
 .../title/parser/TitleFacetFromValueFacet.java     |   4 +-
 .../ViewModelFacetForDomainObjectAnnotation.java   |   2 +-
 .../viewmodel/ViewModelFacetForJavaRecord.java     |   2 +-
 .../ViewModelFacetForXmlRootElementAnnotation.java |   2 +-
 .../metamodel/interactions/InteractionHead.java    |  16 +--
 .../interactions/managed/ActionInteraction.java    |   4 +-
 .../interactions/managed/ManagedAction.java        |   2 +-
 .../interactions/managed/ManagedMember.java        |   2 +-
 .../managed/PendingParamsSnapshot.java             |   2 +-
 .../interactions/val/ObjectValidityContext.java    |   2 +-
 .../interactions/vis/ObjectVisibilityContext.java  |   2 +-
 .../core/metamodel/object/Bookmarkable.java        |   2 +-
 .../core/metamodel/object/ManagedObject.java       |  29 +++---
 ...gedObjectOther.java => ManagedObjectOther.java} |  43 +++++---
 ...pecified.java => ManagedObjectUnspecified.java} |  19 +---
 .../core/metamodel/object/ManagedObjects.java      |  16 +--
 .../core/metamodel/object/MmAssertionUtils.java    |   6 +-
 .../core/metamodel/object/MmDebugUtils.java        |   2 +-
 .../core/metamodel/object/MmEntityUtils.java       |  20 ++--
 .../core/metamodel/object/MmHintUtils.java         |   2 +-
 .../core/metamodel/object/MmSpecUtils.java         |   6 +-
 .../core/metamodel/object/MmValueUtils.java        |   4 +-
 .../core/metamodel/object/MmVisibilityUtils.java   |   2 +-
 .../core/metamodel/object/_Compliance.java         | 113 +++++++++++++++++++++
 .../core/metamodel/object/_InternalTitleUtil.java  |   8 +-
 .../core/metamodel/object/_ManagedObjectEmpty.java |   2 +-
 .../object/_ManagedObjectEntityBookmarked.java     |   8 +-
 .../object/_ManagedObjectEntityHybrid.java         |  20 ++--
 .../object/_ManagedObjectEntityTransient.java      |   2 +-
 .../metamodel/object/_ManagedObjectSpecified.java  | 102 ++-----------------
 .../core/metamodel/object/_ManagedObjectValue.java |   2 +-
 .../metamodel/object/_ManagedObjectViewmodel.java  |   2 +-
 .../objectmanager/ObjectCreatorFactory.java        |   4 +-
 .../metamodel/objectmanager/ObjectManager.java     |   6 +-
 .../memento/ObjectMementoSingular.java             |   4 +-
 .../authorization/AuthorizationFacetAbstract.java  |   4 +-
 .../services/title/TitleServiceDefault.java        |   4 +-
 .../metamodel/spec/HasObjectSpecification.java     |  22 ++--
 .../core/metamodel/spec/feature/ObjectAction.java  |   8 +-
 .../core/metamodel/spec/feature/ObjectFeature.java |   7 ++
 .../metamodel/spec/impl/ObjectActionDefault.java   |   2 +-
 .../metamodel/spec/impl/ObjectActionMixedIn.java   |   2 +-
 .../spec/impl/ObjectSpecificationDefault.java      |   2 +-
 .../metamodel/spec/impl/_MembersAsColumns.java     |   2 +-
 .../tabular/internal/DataTableInternal.java        |   2 +-
 .../causeway/core/metamodel/util/Facets.java       |   2 +-
 .../core/metamodel/util/snapshot/XmlSnapshot.java  |  10 +-
 .../RecreatableObjectFacetFactoryTest.java         |   2 +-
 .../core/metamodel/object/ManagedObjectTest.java   |   4 +-
 .../command/CommandExecutorServiceDefault.java     |   4 +-
 .../command/SchemaValueMarshallerDefault.java      |   2 +-
 .../executor/MemberExecutorServiceDefault.java     |   4 +-
 .../bootstrap/MenuBarsServiceBootstrap.java        |  12 +--
 .../publish/LifecycleCallbackNotifier.java         |   2 +-
 .../wrapper/WrapperFactoryDefault.java             |   8 +-
 .../handlers/DomainObjectInvocationHandler.java    |  16 +--
 .../menubars/bootstrap/MenuBarsServiceBSTest.java  |   2 +-
 .../changetracking/EntityChangeTrackerDefault.java |  24 ++---
 .../commons/integration/changetracking/_Xray.java  |   2 +-
 .../version/EntityVersionAccessorDefault.java      |   2 +-
 .../jdo/datanucleus/changetracking/_Utils.java     |   2 +-
 .../interaction/DomainObjectTesterFactory.java     |   6 +-
 .../DomainModelTest_usingGoodDomain.java           |   2 +-
 .../JpaGeneratedLongIdEntityLifecycleTest.java     |   2 +-
 ...JpaNonGeneratedStringIdEntityLifecycleTest.java |   2 +-
 .../value/ActionInteractionProbeImpl.java          |   4 +-
 .../value/PropertyInteractionProbeImpl.java        |   2 +-
 .../viewers/common/wkt/InteractionTestWkt.java     |   2 +-
 .../viewer/commons/model/action/UiActionForm.java  |   2 +-
 .../viewer/commons/model/layout/UiGridLayout.java  |   4 +-
 .../common/query/meta/CommonMetaFetcher.java       |   8 +-
 .../viewer/controller/ResourceController.java      |   4 +-
 .../domainobjects/DomainObjectReprRenderer.java    |  22 ++--
 .../domainobjects/DomainServiceLinkTo.java         |   2 +-
 .../rendering/domainobjects/ListReprRenderer.java  |   2 +-
 .../domainobjects/ObjectActionReprRenderer.java    |   6 +-
 .../domainobjects/ObjectAndActionInvocation.java   |   4 +-
 .../ObjectCollectionReprRenderer.java              |   2 +-
 .../domainobjects/ObjectPropertyReprRenderer.java  |   4 +-
 .../domainobjects/ScalarValueReprRenderer.java     |   2 +-
 ...ntentNegotiationServiceOrgApacheCausewayV2.java |  10 +-
 .../service/valuerender/JsonValueConverter.java    |   2 +-
 .../JsonValueEncoderServiceDefault.java            |  19 ++--
 .../domainobjects/JsonValueEncoderTest.java        |  14 +--
 .../resources/DomainObjectResourceServerside.java  |   4 +-
 .../resources/ObjectAdapterUpdateHelper.java       |   6 +-
 .../wicket/model/models/ActionResultModel.java     |   2 +-
 .../viewer/wicket/model/models/ParameterModel.java |   2 +-
 .../viewer/wicket/model/models/UiObjectWkt.java    |   2 +-
 .../viewer/wicket/model/models/ValueModel.java     |   2 +-
 .../interaction/HasBookmarkedOwnerAbstract.java    |   2 +-
 .../interaction/act/ActionInteractionWkt.java      |   2 +-
 .../interaction/prop/PropertyInteractionWkt.java   |   2 +-
 .../markup/MarkupAttributePanelFactories.java      |   2 +-
 .../present/ajaxtable/columns/SingularColumn.java  |   2 +-
 .../wicket/ui/components/layout/bs/col/Col.java    |   2 +-
 .../components/object/fieldset/PropertyGroup.java  |   2 +-
 .../object/icontitle/ObjectIconAndTitlePanel.java  |   8 +-
 .../ui/components/table/CausewayAjaxDataTable.java |   2 +-
 .../ui/components/unknown/UnknownModelPanel.java   |   2 +-
 .../components/widgets/actionlink/ActionLink.java  |   2 +-
 .../viewer/wicket/ui/exec/MediatorFactory.java     |   2 +-
 114 files changed, 432 insertions(+), 400 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/_testing/MetaModelContext_forTesting.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/_testing/MetaModelContext_forTesting.java
index 0ab8804d2e3..98d96ba2063 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/_testing/MetaModelContext_forTesting.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/_testing/MetaModelContext_forTesting.java
@@ -559,7 +559,7 @@ private final Map<String, ManagedObject> collectBeansOfKnownSort() {
         services.stream()
         .map(service->ManagedObject.service(service.specification, service.pojo))
         .forEach(serviceAdapter->
-            map.put(serviceAdapter.getSpecification().logicalTypeName(), serviceAdapter));
+            map.put(serviceAdapter.objSpec().logicalTypeName(), serviceAdapter));
         return map;
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/commons/UtilStr.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/commons/UtilStr.java
index a8297043f41..2f4c677e6ae 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/commons/UtilStr.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/commons/UtilStr.java
@@ -32,7 +32,7 @@ public class UtilStr {
     /**
      * String representation of bookmark for entities (otherwise empty string is returned).
      */
-    public static String entityAsStr(Bookmark bookmark, SpecificationLoader specificationLoader) {
+    public static String entityAsStr(final Bookmark bookmark, final SpecificationLoader specificationLoader) {
         var logicalTypeName = bookmark.logicalTypeName();
         var isEntity = specificationLoader
                             .lookupLogicalType(logicalTypeName)
@@ -57,17 +57,17 @@ public static String namedArgStr(
         return namedArgStr(paramName, managedObject);
     }
 
-    public static String namedArgStr(String paramName, ManagedObject managedObject) {
+    public static String namedArgStr(final String paramName, final ManagedObject managedObject) {
         if (isSensitiveName(paramName)) {
             return "********";
         }
-        if(managedObject.getSpecialization().isEmpty()) {
+        if(managedObject.specialization().isEmpty()) {
             return "<none>";
         }
         return managedObject.getTitle();
     }
 
-    private static boolean isSensitiveName(String name) {
+    private static boolean isSensitiveName(final String name) {
         return name.equalsIgnoreCase("password") ||
                 name.equalsIgnoreCase("secret") ||
                 name.equalsIgnoreCase("apikey") ||
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/context/MetaModelContext_usingSpring.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/context/MetaModelContext_usingSpring.java
index 752b7f6fa8f..fa8b51e936b 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/context/MetaModelContext_usingSpring.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/context/MetaModelContext_usingSpring.java
@@ -195,7 +195,7 @@ private Map<String, ManagedObject> collectBeansOfKnownSort() {
                 .streamRegisteredBeans()
                 .map(this::toManagedObject)
                 .collect(Collectors.toMap(
-                        service->service.getSpecification().logicalTypeName(),
+                        service->service.objSpec().logicalTypeName(),
                         v->v,
                         (o,n)->n,
                         LinkedHashMap::new));
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/execution/PropertyModifier.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/execution/PropertyModifier.java
index 600ffebcb5f..8c3a9a29c39 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/execution/PropertyModifier.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/execution/PropertyModifier.java
@@ -180,7 +180,7 @@ public Object execute(final PropertyEdit currentExecution) {
         final ManagedObject newValueAfterEventPolling =
                 isValueModifiedByEvent
                         // properly handles the pojo==null case
-                        ? ManagedObject.adaptSingular(newValue.getSpecification(), newValuePojoPossiblyUpdated)
+                        ? ManagedObject.adaptSingular(newValue.objSpec(), newValuePojoPossiblyUpdated)
                         : newValue;
 
         // set event onto the execution
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/invocation/IdentifierUtil.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/invocation/IdentifierUtil.java
index 07804d782b9..cb4066dc52f 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/invocation/IdentifierUtil.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/actions/action/invocation/IdentifierUtil.java
@@ -108,7 +108,7 @@ public String logicalMemberIdentifierFor(
                 if (interactionHead instanceof ActionInteractionHead) {
                     ObjectAction objectActionOnMixee =
                             ((ActionInteractionHead) interactionHead).getMetaModel();
-                    ObjectSpecification specificationOfMixee = interactionHead.owner().getSpecification();
+                    ObjectSpecification specificationOfMixee = interactionHead.owner().objSpec();
                     return logicalMemberIdentifierFor(specificationOfMixee, objectActionOnMixee);
                 }
             }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/collections/CollectionFacet.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/collections/CollectionFacet.java
index faca9e2a2d7..e92655ada79 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/collections/CollectionFacet.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/collections/CollectionFacet.java
@@ -104,7 +104,7 @@ Object populatePojo(
 
     public static Optional<CollectionFacet> lookup(final @Nullable ManagedObject container) {
         return container!=null
-            ? container.getSpecification().lookupFacet(CollectionFacet.class)
+            ? container.objSpec().lookupFacet(CollectionFacet.class)
             : Optional.empty();
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/choices/ChoicesFacetFromBoundedAbstract.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/choices/ChoicesFacetFromBoundedAbstract.java
index 106e72ecfef..4723aaa38d1 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/choices/ChoicesFacetFromBoundedAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/choices/ChoicesFacetFromBoundedAbstract.java
@@ -79,7 +79,7 @@ public String invalidates(final ValidityContext context) {
         if(!(getFacetHolder() instanceof ObjectSpecification)) return null;
 
         final ObjectSpecification objectSpec = getObjectSpecification();
-        return objectSpec == target.getSpecification()? null: "Invalid type";
+        return objectSpec == target.objSpec()? null: "Invalid type";
     }
 
     private ObjectSpecification getObjectSpecification() {
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/GridFacetDefault.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/GridFacetDefault.java
index 7c4b103ad22..4c2440a27e0 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/GridFacetDefault.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/grid/GridFacetDefault.java
@@ -85,12 +85,12 @@ public void visitAttributes(final BiConsumer<String, Object> visitor) {
 
     private void guardAgainstObjectOfDifferentType(final @Nullable ManagedObject objectAdapter) {
         if(ManagedObjects.isNullOrUnspecifiedOrEmpty(objectAdapter)) return; // cannot introspect
-        if(!getSpecification().equals(objectAdapter.getSpecification())) {
+        if(!getSpecification().equals(objectAdapter.objSpec())) {
             throw _Exceptions.unrecoverable(
                     "getGrid(adapter) was called passing an adapter (type: %s), "
                     + "for which this GridFacet (type: %s) is not responsible; "
                     + "indicates that some framework internals are wired up in a wrong way",
-                    objectAdapter.getSpecification().getCorrespondingClass().getName(),
+                    objectAdapter.objSpec().getCorrespondingClass().getName(),
                     getSpecification().getCorrespondingClass().getName());
         }
     }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/objectvalidprops/impl/ObjectValidPropertiesFacetImpl.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/objectvalidprops/impl/ObjectValidPropertiesFacetImpl.java
index 7b174852590..086d41fd642 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/objectvalidprops/impl/ObjectValidPropertiesFacetImpl.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/objectvalidprops/impl/ObjectValidPropertiesFacetImpl.java
@@ -45,7 +45,7 @@ public String invalidReason(
         final StringBuilder buf = new StringBuilder();
         final ManagedObject adapter = context.target();
 
-        adapter.getSpecification().streamProperties(MixedIn.EXCLUDED)
+        adapter.objSpec().streamProperties(MixedIn.EXCLUDED)
         .filter(property->property.isVisible(adapter, context.initiatedBy(), where).isVetoed()) // ignore hidden properties
         .filter(property->property.isUsable(adapter, context.initiatedBy(), where).isVetoed())  // ignore disabled properties
         .forEach(property->{
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/projection/ident/CssClassFacetFromProjectionFacet.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/projection/ident/CssClassFacetFromProjectionFacet.java
index 6ea5f836afa..1b60325b1e3 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/projection/ident/CssClassFacetFromProjectionFacet.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/projection/ident/CssClassFacetFromProjectionFacet.java
@@ -26,13 +26,13 @@
 import org.apache.causeway.core.metamodel.facets.object.projection.ProjectionFacet;
 import org.apache.causeway.core.metamodel.object.ManagedObject;
 
-public class CssClassFacetFromProjectionFacet 
+public class CssClassFacetFromProjectionFacet
 extends CssClassFacetAbstract {
 
     private final ProjectionFacet projectionFacet;
 
     public CssClassFacetFromProjectionFacet(
-            final ProjectionFacet projectionFacet, 
+            final ProjectionFacet projectionFacet,
             final FacetHolder holder) {
         super(holder);
         this.projectionFacet = projectionFacet;
@@ -41,9 +41,9 @@ public CssClassFacetFromProjectionFacet(
     @Override
     public String cssClass(final ManagedObject targetAdapter) {
         var projectedAdapter = projectionFacet.projected(targetAdapter);
-        var cssClassFacet = projectedAdapter.getSpecification().getFacet(CssClassFacet.class);
-        return cssClassFacet != null 
-                ? cssClassFacet.cssClass(projectedAdapter) 
+        var cssClassFacet = projectedAdapter.objSpec().getFacet(CssClassFacet.class);
+        return cssClassFacet != null
+                ? cssClassFacet.cssClass(projectedAdapter)
                 : null;
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/projection/ident/IconFacetFromProjectionFacet.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/projection/ident/IconFacetFromProjectionFacet.java
index b66ae0c61f9..97e545d419f 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/projection/ident/IconFacetFromProjectionFacet.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/projection/ident/IconFacetFromProjectionFacet.java
@@ -43,7 +43,7 @@ public IconFacetFromProjectionFacet(
     @Override
     public String iconName(final ManagedObject targetAdapter) {
         var projectedAdapter = projectionFacet.projected(targetAdapter);
-        return projectedAdapter.getSpecification().getIconName(projectedAdapter);
+        return projectedAdapter.objSpec().getIconName(projectedAdapter);
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/methods/TitleFacetViaTitleMethod.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/methods/TitleFacetViaTitleMethod.java
index 032e3bfdd79..db63535b168 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/methods/TitleFacetViaTitleMethod.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/methods/TitleFacetViaTitleMethod.java
@@ -93,7 +93,7 @@ public String title(final TitleRenderRequest titleRenderRequest) {
                     .map(CausewaySystemEnvironment::isUnitTesting)
                     .orElse(false);
             if(!isUnitTesting) {
-                log.warn("Failed Title {}", owningAdapter.getSpecification(), ex);
+                log.warn("Failed Title {}", owningAdapter.objSpec(), ex);
             }
             return "Failed Title";
         }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/parser/TitleFacetFromValueFacet.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/parser/TitleFacetFromValueFacet.java
index e4282d389ba..cb7643b06c1 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/parser/TitleFacetFromValueFacet.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/title/parser/TitleFacetFromValueFacet.java
@@ -57,7 +57,7 @@ public String title(final TitleRenderRequest renderRequest) {
          * and alternatively object-support method 'title()',
          * by letting the SpecificationLoader introspect enum types and populate the meta-model
          * with TitleFacets (that have higher priority than this one). */
-        if(renderRequest.object().getSpecification().getCorrespondingClass().isEnum()) {
+        if(renderRequest.object().objSpec().getCorrespondingClass().isEnum()) {
             return Enums.getFriendlyNameOf((Enum<?>)pojo);
         }
 
@@ -89,7 +89,7 @@ public String title(final TitleRenderRequest renderRequest) {
             .map(renderer->(Renderer) renderer)
             .map(renderer->renderer.titlePresentation(valueFacet.createValueSemanticsContext(feature), pojo))
             .orElseGet(()->String.format("Value type %s has no value semantics for title rendering.",
-                    renderRequest.object().getSpecification().getCorrespondingClass()));
+                    renderRequest.object().objSpec().getCorrespondingClass()));
 
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForDomainObjectAnnotation.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForDomainObjectAnnotation.java
index 1b52288581d..f5a93d6ec47 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForDomainObjectAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForDomainObjectAnnotation.java
@@ -127,7 +127,7 @@ public String serialize(final ManagedObject viewModel) {
 
         final _Mementos.Memento memento = newMemento();
 
-        var viewmodelSpec = viewModel.getSpecification();
+        var viewmodelSpec = viewModel.objSpec();
 
         streamPersistableProperties(viewmodelSpec)
         .forEach(property->{
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForJavaRecord.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForJavaRecord.java
index 607c5d9fbb0..5e8b1234bbf 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForJavaRecord.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForJavaRecord.java
@@ -95,7 +95,7 @@ public String serialize(final ManagedObject viewModel) {
 
         final _Mementos.Memento memento = newMemento();
 
-        var viewmodelSpec = viewModel.getSpecification();
+        var viewmodelSpec = viewModel.objSpec();
 
         streamRecordComponents(viewmodelSpec)
         .forEach(association->{
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForXmlRootElementAnnotation.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForXmlRootElementAnnotation.java
index 066c83b5b1d..2960f16c26d 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForXmlRootElementAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForXmlRootElementAnnotation.java
@@ -81,7 +81,7 @@ protected String serialize(final ManagedObject managedObject) {
                     + "--- XML ---\n"
                     + "%s"
                     + "-----------\n",
-                    managedObject.getSpecification().logicalTypeName(),
+                    managedObject.objSpec().logicalTypeName(),
                     xml);
         });
         return encoded;
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/InteractionHead.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/InteractionHead.java
index 87ebcc2b45f..eb502d3d4a0 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/InteractionHead.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/InteractionHead.java
@@ -67,31 +67,31 @@ default Optional<ManagedObject> getMixee() {
     }
 
     // -- HELPER
-    
+
     /**
-     * Immutable implementation of {@link InteractionHead} with consistency checks. 
+     * Immutable implementation of {@link InteractionHead} with consistency checks.
      */
     record InteractionHeadRecord(
         ManagedObject owner,
         ManagedObject target) implements InteractionHead {
-       
+
         // canonical constructor with consistency checks
         public InteractionHeadRecord(
-            ManagedObject owner,
-            ManagedObject target) {
+            final ManagedObject owner,
+            final ManagedObject target) {
             if(ManagedObjects.isSpecified(owner)
-                && owner.getSpecification().getBeanSort().isMixin()) {
+                && owner.objSpec().getBeanSort().isMixin()) {
                 throw _Exceptions.unrecoverable("unexpected: owner is a mixin %s", owner);
             }
             if(ManagedObjects.isSpecified(target)
-                && target.getSpecification().getBeanSort().isMixin()
+                && target.objSpec().getBeanSort().isMixin()
                 && target.getPojo()==null) {
                 throw _Exceptions.unrecoverable("target not spec. %s", target);
             }
             this.owner = owner;
             this.target = target;
         }
-        
+
     }
 
 }
\ No newline at end of file
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/ActionInteraction.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/ActionInteraction.java
index ca83cca982f..86e3fb2962e 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/ActionInteraction.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/ActionInteraction.java
@@ -106,7 +106,7 @@ public static ActionInteraction startAsBoundToProperty(
                 //XXX guard against memberId collision,
                 // such that if there is a conflict, the conventional member wins
                 // (maybe improve programming model so this cannot happen)
-                && propertyOwner.getSpecification().getAction(memberId, MixedIn.INCLUDED).isEmpty()) {
+                && propertyOwner.objSpec().getAction(memberId, MixedIn.INCLUDED).isEmpty()) {
 
             var compositeValueNullable = prop.get(propertyOwner);
             var compositeValue =
@@ -144,7 +144,7 @@ public static ActionInteraction startAsBoundToParameter(
                 //XXX guard against memberId collision,
                 // such that if there is a conflict, the conventional member wins
                 // (maybe improve programming model so this cannot happen)
-                && actionOwner.getSpecification().getAction(memberId, MixedIn.INCLUDED).isEmpty()) {
+                && actionOwner.objSpec().getAction(memberId, MixedIn.INCLUDED).isEmpty()) {
 
             var compositeValueNullable = parameterNegotiationModel.getParamValue(paramIndex);
             var compositeValue =
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/ManagedAction.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/ManagedAction.java
index fba5113226e..169c3282d42 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/ManagedAction.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/ManagedAction.java
@@ -93,7 +93,7 @@ private ManagedAction(
             may still want to provide an action result, that does not need the mixee instance to be produced;
             eg. delete ApplicationUser mixin that returns a collection of all remaining users
             after deleting the selected one */
-        if(!owner.getSpecialization().isEntity()) {
+        if(!owner.specialization().isEntity()) {
             _Assert.assertFalse(ManagedObjects.isNullOrUnspecifiedOrEmpty(owner), ()->
                     String.format("cannot create managed-action for action %s with an empty owner %s",
                             action.getFeatureIdentifier(),
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/ManagedMember.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/ManagedMember.java
index 4e5bf03c6aa..d4511dd8fb9 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/ManagedMember.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/ManagedMember.java
@@ -156,7 +156,7 @@ protected static <T extends ObjectMember> Optional<T> lookup(
             final Identifier.@NonNull Type memberType,
             final @NonNull String memberId) {
 
-        var onwerSpec = owner.getSpecification();
+        var onwerSpec = owner.objSpec();
         switch (memberType) {
         case ACTION:     return _Casts.uncheckedCast(onwerSpec.getAction(memberId));
         case PROPERTY:   return _Casts.uncheckedCast(onwerSpec.getProperty(memberId));
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/PendingParamsSnapshot.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/PendingParamsSnapshot.java
index dabe115db39..745cd59fefe 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/PendingParamsSnapshot.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/managed/PendingParamsSnapshot.java
@@ -145,7 +145,7 @@ private Can<Bookmark> bookmark(
                                 paramModel.getMetaModel().getFeatureIdentifier()));
                 if(isPlural) {
                     cardinalityConstraints[paramModel.paramIndex()] =
-                            Objects.requireNonNull(((PackedManagedObject)paramValue).getLogicalType());
+                            Objects.requireNonNull(paramValue.logicalType());
                 }
             }
             return isPlural
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/val/ObjectValidityContext.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/val/ObjectValidityContext.java
index a23d24aba80..9fafe3e4c07 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/val/ObjectValidityContext.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/val/ObjectValidityContext.java
@@ -49,7 +49,7 @@ public ObjectValidityContext(
         this(InteractionContextType.OBJECT_VALIDATE,
                 InteractionHead.regular(targetAdapter),
                 identifier,
-                ()->targetAdapter.getSpecification().getSingularName(),
+                ()->targetAdapter.objSpec().getSingularName(),
                 initiatedBy);
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/vis/ObjectVisibilityContext.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/vis/ObjectVisibilityContext.java
index d4e5a84411c..4f542b7b043 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/vis/ObjectVisibilityContext.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/interactions/vis/ObjectVisibilityContext.java
@@ -55,7 +55,7 @@ public static ObjectVisibilityContext createForRegular(
             final Where where) {
         return new ObjectVisibilityContext(
                 InteractionHead.regular(domainObject),
-                domainObject.getSpecification().getFeatureIdentifier(),
+                domainObject.objSpec().getFeatureIdentifier(),
                 initiatedBy,
                 where,
                 InteractionUtils.renderPolicy(domainObject));
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/Bookmarkable.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/Bookmarkable.java
index 178da70a86f..3bf8f54dbe0 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/Bookmarkable.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/Bookmarkable.java
@@ -44,7 +44,7 @@ default boolean isBookmarkSupported() {
 
     default Bookmark getBookmarkElseFail() {
         return getBookmark().orElseThrow(()->
-              _Exceptions.unrecoverable("failed to bookmark %s", ((ManagedObject)this).getSpecification()));
+              _Exceptions.unrecoverable("failed to bookmark %s", ((ManagedObject)this).objSpec()));
     }
 
     /**
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/ManagedObject.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/ManagedObject.java
index e9bdc11c4c0..678ce593e87 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/ManagedObject.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/ManagedObject.java
@@ -20,8 +20,8 @@
 
 import java.util.List;
 import java.util.Optional;
-import java.util.function.Supplier;
 
+import org.jspecify.annotations.NonNull;
 import org.jspecify.annotations.Nullable;
 
 import org.apache.causeway.applib.fa.FontAwesomeLayers;
@@ -40,7 +40,6 @@
 import org.apache.causeway.core.metamodel.specloader.SpecificationLoader;
 
 import lombok.Getter;
-import org.jspecify.annotations.NonNull;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.log4j.Log4j2;
 
@@ -316,16 +315,18 @@ public static Specialization inferFrom(
      * Returns the specific {@link Specialization} this {@link ManagedObject} implements,
      * which governs this object's behavior.
      */
-    Specialization getSpecialization();
+    Specialization specialization();
+
+    @Deprecated default Specialization getSpecialization() { return specialization(); }
+
     @Override default BookmarkPolicy getBookmarkPolicy() {
-        return getSpecialization().getBookmarkPolicy();
+        return specialization().getBookmarkPolicy();
     }
 
     /**
      * Returns the specification that details the structure (meta-model) of this object.
      */
-    @Override
-    ObjectSpecification getSpecification();
+    @Override ObjectSpecification objSpec();
 
     /**
      * Returns the adapted domain object, the 'plain old java' object this managed object
@@ -338,11 +339,9 @@ default EntityState getEntityState() {
         return EntityState.NOT_PERSISTABLE;
     }
 
-    Supplier<ManagedObject> asSupplier();
-
     /**
-     * Unary operator asserting that {@code pojo} and {@link #getSpecification()} are
-     * compliant with the policies from {@link #getSpecialization()}.
+     * Unary operator asserting that {@code pojo} and {@link #objSpec()} are
+     * compliant with the policies from {@link #specialization()}.
      */
     <T> T assertCompliance(@NonNull T pojo);
 
@@ -361,11 +360,11 @@ default EntityState getEntityState() {
      * May return <code>null</code> if no icon is specified.
      */
     default String getIconName() {
-        return getSpecification().getIconName(this);
+        return objSpec().getIconName(this);
     }
 
     default ObjectIcon getIcon() {
-        return getSpecification().getIcon(this);
+        return objSpec().getIcon(this);
     }
 
     /**
@@ -374,7 +373,7 @@ default ObjectIcon getIcon() {
      */
     default Either<ObjectIcon, FontAwesomeLayers> eitherIconOrFaLayers() {
         var iconName = getIconName();
-        var faLayers = getSpecification().getFaLayers(this).orElse(null);
+        var faLayers = objSpec().getFaLayers(this).orElse(null);
         if (iconName != null
                 || faLayers == null) {
             return Either.left(getIcon());
@@ -398,7 +397,7 @@ default Either<ManagedObject, ManagedObject> asEitherWithOrWithoutMemoizedBookma
      * @see ManagedObject.Specialization.PojoPolicy#NO_POJO
      */
     static ManagedObject unspecified() {
-        return _ManagedObjectUnspecified.INSTANCE;
+        return ManagedObjectUnspecified.INSTANCE;
     }
     /**
      * EMPTY
@@ -518,7 +517,7 @@ private static ManagedObject other(
             final @NonNull ObjectSpecification spec,
             final @Nullable Object pojo) {
         return pojo != null
-                ? new _ManagedObjectOther(spec, pojo)
+                ? new ManagedObjectOther(spec, pojo)
                 : empty(spec);
     }
     /**
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectOther.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/ManagedObjectOther.java
similarity index 63%
rename from core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectOther.java
rename to core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/ManagedObjectOther.java
index f95ae8a2824..f90a4048ff0 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectOther.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/ManagedObjectOther.java
@@ -18,36 +18,47 @@
  */
 package org.apache.causeway.core.metamodel.object;
 
+import org.jspecify.annotations.NonNull;
+
 import org.apache.causeway.commons.internal.assertions._Assert;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 
-import lombok.Getter;
-import org.jspecify.annotations.NonNull;
-import lombok.experimental.Accessors;
-
 /**
  * (package private) specialization corresponding to {@link Specialization#OTHER}
  * @see ManagedObject.Specialization#OTHER
  */
-final class _ManagedObjectOther
-extends _ManagedObjectSpecified
-implements Bookmarkable.NoBookmark {
+record ManagedObjectOther(
+    @NonNull ObjectSpecification objSpec,
+    @NonNull Object pojo)
+implements ManagedObject, Bookmarkable.NoBookmark {
 
-    @Getter(onMethod_ = {@Override}) @Accessors(makeFinal = true)
-    private final @NonNull Object pojo;
-
-    _ManagedObjectOther(
-            final ObjectSpecification spec,
+    ManagedObjectOther(
+            final ObjectSpecification objSpec,
             final Object pojo) {
-        super(ManagedObject.Specialization.OTHER, spec);
-        _Assert.assertTrue(!spec.isValue());
-        _Assert.assertTrue(!spec.isEntityOrViewModel());
+        this.objSpec = objSpec;
+        _Assert.assertTrue(!objSpec.isValue());
+        _Assert.assertTrue(!objSpec.isEntityOrViewModel());
         this.pojo = assertCompliance(pojo);
     }
 
     @Override
     public String getTitle() {
-        return "other object, not recognized by the framework's meta-model";
+        return "other object, not recognized by the framework";
+    }
+
+    @Override
+    public Specialization specialization() {
+        return ManagedObject.Specialization.OTHER;
+    }
+
+    @Override
+    public <T> T assertCompliance(@NonNull final T pojo) {
+        return _Compliance.assertCompliance(objSpec, specialization(), pojo);
+    }
+
+    @Override
+    public Object getPojo() {
+        return pojo;
     }
 
 }
\ No newline at end of file
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectUnspecified.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/ManagedObjectUnspecified.java
similarity index 80%
rename from core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectUnspecified.java
rename to core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/ManagedObjectUnspecified.java
index 75493ca5baf..d7cec6ce9c0 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectUnspecified.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/ManagedObjectUnspecified.java
@@ -19,29 +19,25 @@
 package org.apache.causeway.core.metamodel.object;
 
 import java.util.Objects;
-import java.util.function.Supplier;
-
 import org.apache.causeway.commons.internal.exceptions._Exceptions;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 
-import org.jspecify.annotations.NonNull;
-
 /**
  * (package private) specialization corresponding to {@link Specialization#UNSPECIFIED}
  * @see ManagedObject.Specialization#UNSPECIFIED
  */
-final class _ManagedObjectUnspecified
+record ManagedObjectUnspecified()
 implements ManagedObject, Bookmarkable.NoBookmark {
 
-    static final ManagedObject INSTANCE = new _ManagedObjectUnspecified();
+    static final ManagedObject INSTANCE = new ManagedObjectUnspecified();
 
     @Override
-    public Specialization getSpecialization() {
+    public Specialization specialization() {
         return Specialization.UNSPECIFIED;
     }
 
     @Override
-    public ObjectSpecification getSpecification() {
+    public ObjectSpecification objSpec() {
         throw _Exceptions.unsupportedOperation();
     }
 
@@ -51,12 +47,7 @@ public Object getPojo() {
     }
 
     @Override
-    public Supplier<ManagedObject> asSupplier() {
-        return ()->this;
-    }
-
-    @Override
-    public <T> T assertCompliance(final @NonNull T pojo) {
+    public <T> T assertCompliance(final T pojo) {
         return pojo; // no-op
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/ManagedObjects.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/ManagedObjects.java
index 705eb56f766..4f13f96df94 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/ManagedObjects.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/ManagedObjects.java
@@ -58,8 +58,8 @@ public final class ManagedObjects {
     public boolean isNullOrUnspecifiedOrEmpty(final @Nullable ManagedObject adapter) {
         if(adapter==null
                 || adapter==ManagedObject.unspecified()
-                || adapter.getSpecialization()==null
-                || adapter.getSpecialization().isEmpty()) {
+                || adapter.specialization()==null
+                || adapter.specialization().isEmpty()) {
             return true;
         }
         if(adapter instanceof PackedManagedObject) {
@@ -108,7 +108,7 @@ public Optional<ManagedObject> asSpecified(final @Nullable ManagedObject adapter
      */
     public Optional<ManagedObject> asScalar(final @Nullable ManagedObject adapter) {
         return asSpecified(adapter)
-                .filter(obj->!obj.getSpecialization().isPacked());
+                .filter(obj->!obj.specialization().isPacked());
     }
 
     /**
@@ -118,7 +118,7 @@ public Optional<ManagedObject> asScalar(final @Nullable ManagedObject adapter) {
      */
     public Optional<ManagedObject> asScalarNonEmpty(final @Nullable ManagedObject adapter) {
         return asScalar(adapter)
-                .filter(obj->!obj.getSpecialization().isEmpty());
+                .filter(obj->!obj.specialization().isEmpty());
     }
 
     /**
@@ -172,14 +172,14 @@ public boolean isInstanceOf(
             return ((PackedManagedObject)object).unpack().stream()
             .allMatch(element->isInstanceOf(element, elementType));
         }
-        var objectActualType = ClassUtils.resolvePrimitiveIfNecessary(object.getSpecification().getCorrespondingClass());
+        var objectActualType = ClassUtils.resolvePrimitiveIfNecessary(object.objSpec().getCorrespondingClass());
         return upperBound.isAssignableFrom(objectActualType);
     }
 
     // -- IDENTIFICATION
 
     public Optional<ObjectSpecification> spec(final @Nullable ManagedObject managedObject) {
-        return isSpecified(managedObject) ? Optional.of(managedObject.getSpecification()) : Optional.empty();
+        return isSpecified(managedObject) ? Optional.of(managedObject.objSpec()) : Optional.empty();
     }
 
     public Optional<Bookmark> bookmark(final @Nullable ManagedObject managedObject) {
@@ -240,7 +240,7 @@ public String stringifyElseUnidentified(
             final @NonNull String separator) {
         return stringify(managedObject, separator)
                 .orElseGet(()->isSpecified(managedObject)
-                        ? managedObject.getSpecification().logicalTypeName() + separator + "?"
+                        ? managedObject.objSpec().logicalTypeName() + separator + "?"
                         : "?" + separator + "?");
     }
 
@@ -396,7 +396,7 @@ public Try<String> imperativeText(
             return Try.success(null);
         }
 
-        var mmc = object.getSpecification().getMetaModelContext();
+        var mmc = object.objSpec().getMetaModelContext();
 
         var result =  Try.call(()->{
             final Object returnValue = MmInvokeUtils.invokeNoArg(method.method(), object);
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmAssertionUtils.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmAssertionUtils.java
index 42f0e54b939..7b547168bb0 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmAssertionUtils.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmAssertionUtils.java
@@ -42,7 +42,7 @@ public void assertExactTypeSpecification(final @Nullable ManagedObject obj) {
         }
         var pojo = ManagedObjects.peekAtPojoOf(obj);
         var requiredType = pojo.getClass();
-        var actualSpec = obj.getSpecification();
+        var actualSpec = obj.objSpec();
         _Assert.assertEquals(requiredType, actualSpec.getCorrespondingClass());
     }
 
@@ -89,7 +89,7 @@ public void assertExactType(
                 return object;
             }
             var upperBound = ClassUtils.resolvePrimitiveIfNecessary(elementType.getCorrespondingClass());
-            var objectActualType = ClassUtils.resolvePrimitiveIfNecessary(object.getSpecification().getCorrespondingClass());
+            var objectActualType = ClassUtils.resolvePrimitiveIfNecessary(object.objSpec().getCorrespondingClass());
             throw _Exceptions.illegalArgument("Object has incompatible type %s, "
                     + "must be an instance of %s.",
                     objectActualType.getName(),
@@ -133,7 +133,7 @@ public void assertSpecifiedAndNotEmpty(final @Nullable ManagedObject adapter) {
     /** check is free of side-effects - also fails on non-attached entities */
     public void assertIsBookmarkSupported(final @Nullable ManagedObject adapter) {
         assertSpecifiedAndNotEmpty(adapter);
-        _Assert.assertFalse(adapter.getSpecialization().getBookmarkPolicy().isNoBookmark(),
+        _Assert.assertFalse(adapter.specialization().getBookmarkPolicy().isNoBookmark(),
                 ()->String.format("object %s does not provide a bookmark", adapter));
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmDebugUtils.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmDebugUtils.java
index 5b6cd717e05..0a21b6ce5cf 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmDebugUtils.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmDebugUtils.java
@@ -92,7 +92,7 @@ public static PropUpdateData propUpdateDataFor(final PropertyNegotiationModel pr
     private static String formatPendingValue(final @Nullable ManagedObject managedObject) {
         return ManagedObjects.isSpecified(managedObject)
                 ? String.format("(%s,cls=%s) pojo=%s",
-                    managedObject.getSpecialization().name(),
+                    managedObject.specialization().name(),
                     managedObject.getCorrespondingClass().getName(),
                     ""+managedObject.getPojo())
                 : "(unspecified) pojo=null";
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmEntityUtils.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmEntityUtils.java
index 4b1ca8a7a72..3a15d768b1e 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmEntityUtils.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmEntityUtils.java
@@ -44,7 +44,7 @@ public Optional<PersistenceStack> getPersistenceStandard(final @Nullable Managed
         if(adapter==null) {
             return Optional.empty();
         }
-        var spec = adapter.getSpecification();
+        var spec = adapter.objSpec();
         if(spec==null || !spec.isEntity()) {
             return Optional.empty();
         }
@@ -62,14 +62,14 @@ public EntityState getEntityState(final @Nullable ManagedObject adapter) {
 
     public void persistInCurrentTransaction(final ManagedObject managedObject) {
         requiresEntity(managedObject);
-        var spec = managedObject.getSpecification();
+        var spec = managedObject.objSpec();
         var entityFacet = spec.entityFacetElseFail();
         entityFacet.persist(managedObject.getPojo());
     }
 
     public void deleteInCurrentTransaction(final ManagedObject managedObject) {
         requiresEntity(managedObject);
-        var spec = managedObject.getSpecification();
+        var spec = managedObject.objSpec();
         var entityFacet = spec.entityFacetElseFail();
         entityFacet.delete(managedObject.getPojo());
     }
@@ -78,7 +78,7 @@ public void requiresEntity(final ManagedObject managedObject) {
         if(ManagedObjects.isNullOrUnspecifiedOrEmpty(managedObject)) {
             throw _Exceptions.illegalArgument("requires an entity object but got null, unspecified or empty");
         }
-        var spec = managedObject.getSpecification();
+        var spec = managedObject.objSpec();
         if(!spec.isEntity()) {
             throw _Exceptions.illegalArgument("not an entity type %s (sort=%s)",
                     spec.getCorrespondingClass(),
@@ -93,7 +93,7 @@ public void requiresEntity(final ManagedObject managedObject) {
      */
     public void ifHasNoOidThenFlush(final @Nullable ManagedObject entity) {
         if(ManagedObjects.isNullOrUnspecifiedOrEmpty(entity)
-                || !entity.getSpecialization().isEntity()
+                || !entity.specialization().isEntity()
                 || entity.isBookmarkMemoized()) {
             return;
         }
@@ -109,7 +109,7 @@ public void ifHasNoOidThenFlush(final @Nullable ManagedObject entity) {
      */
     public boolean isAttachedEntity(final @Nullable ManagedObject entity) {
         return entity!=null
-                ? entity.getSpecialization().isEntity()
+                ? entity.specialization().isEntity()
                     && entity.isBookmarkMemoized()
                     && entity.getEntityState().isAttached()
                 : false;
@@ -133,7 +133,7 @@ public ManagedObject requiresAttached(final @NonNull ManagedObject managedObject
                     EntityState.ATTACHED,
                     entityState,
                     ()-> String.format("entity %s is required to be attached (not detached)",
-                            managedObject.getSpecification().logicalTypeName()));
+                            managedObject.objSpec().logicalTypeName()));
         }
         return managedObject;
     }
@@ -145,7 +145,7 @@ public void requiresWhenFirstIsBookmarkableSecondIsAlso(
         if(!ManagedObjects.isIdentifiable(first) || !ManagedObjects.isSpecified(second)) {
             return;
         }
-        var secondSpec = second.getSpecification();
+        var secondSpec = second.objSpec();
         if(secondSpec.isParented() || !secondSpec.isEntity()) {
             return;
         }
@@ -161,7 +161,7 @@ public void requiresWhenFirstIsBookmarkableSecondIsAlso(
     // -- PROPERTY CHANGE PUBLISHING
 
     public Stream<OneToOneAssociation> streamPropertiesEnabledForChangePublishing(final @NonNull ManagedObject entity) {
-        return entity.getSpecification().streamProperties(MixedIn.EXCLUDED)
+        return entity.objSpec().streamProperties(MixedIn.EXCLUDED)
             .filter(property->!EntityPropertyChangePublishingPolicyFacet.isExcludedFromPublishing(property));
     }
 
@@ -173,7 +173,7 @@ public Stream<PropertyChangeRecordId> streamPropertyChangeRecordIdsForChangePubl
     public Optional<OneToOneAssociation> lookupPropertyEnabledForChangePublishing(
             final @NonNull ManagedObject entity, final String propertyName) {
         return entity
-                .getSpecification()
+                .objSpec()
                 .getProperty(propertyName, MixedIn.EXCLUDED)
                 .filter(property -> !EntityPropertyChangePublishingPolicyFacet.isExcludedFromPublishing(property));
     }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmHintUtils.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmHintUtils.java
index dddd5a7bdd1..a9cab0a5340 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmHintUtils.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmHintUtils.java
@@ -31,7 +31,7 @@ public class MmHintUtils {
 
     public String hintId(final @Nullable ManagedObject adapter) {
         if(ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter)) return null;
-        var spec = adapter.getSpecification();
+        var spec = adapter.objSpec();
         return (spec.isIdentifiable() || spec.isParented())
                 && adapter.getPojo() instanceof HintIdProvider hp
              ? hp.hintId()
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmSpecUtils.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmSpecUtils.java
index 7d6ff50ba56..a841aec8c4f 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmSpecUtils.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmSpecUtils.java
@@ -52,7 +52,7 @@ public ManagedObject enforceMostSpecificSpecOn(final @NonNull ManagedObject obj)
         }
         var pojo = ManagedObjects.peekAtPojoOf(obj);
         var requiredType = pojo.getClass();
-        var currentSpec = obj.getSpecification();
+        var currentSpec = obj.objSpec();
         if(currentSpec.getCorrespondingClass().equals(requiredType)) {
             return obj;
         }
@@ -121,8 +121,8 @@ public boolean isJavaRecord(final @Nullable ObjectSpecification spec) {
 
     /**
      * Whether given {@link ObjectSpecification} represents a FixtureScript (from testing.fixtures.applib).
-     * @implNote if testing.fixtures.applib is not available on the class-path, 
-     *      then given spec cannot be a fixture-script 
+     * @implNote if testing.fixtures.applib is not available on the class-path,
+     *      then given spec cannot be a fixture-script
      */
     public boolean isFixtureScript(final @Nullable ObjectSpecification spec) {
         if(spec==null) return false;
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmValueUtils.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmValueUtils.java
index e904f0e3526..67e786980a9 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmValueUtils.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmValueUtils.java
@@ -61,7 +61,7 @@ public String htmlStringForValueType(
 
         if(!ManagedObjects.isSpecified(adapter)) return "";
 
-        var spec = adapter.getSpecification();
+        var spec = adapter.objSpec();
         var valueFacet = spec.valueFacet().orElse(null);
         if(valueFacet==null) {
             return String.format("missing ValueFacet %s", spec.getCorrespondingClass());
@@ -114,7 +114,7 @@ private <T> Optional<ValueFacet<T>> valueFacet(final @Nullable ObjectSpecificati
 
     private <T> Optional<ValueFacet<T>> valueFacet(final @Nullable ManagedObject valueObject, final Class<T> valueClass) {
         return ManagedObjects.isSpecified(valueObject)
-            ? valueFacet(valueObject.getSpecification(), valueClass)
+            ? valueFacet(valueObject.objSpec(), valueClass)
             : Optional.empty();
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmVisibilityUtils.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmVisibilityUtils.java
index bdf6ac59ccf..8b01347329d 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmVisibilityUtils.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/MmVisibilityUtils.java
@@ -94,7 +94,7 @@ public static boolean isVisible(
             // a choices list could include a null (eg example in ToDoItems#choices1Categorized()); want to show as "visible"
             return true;
         }
-        var spec = adapter.getSpecification();
+        var spec = adapter.objSpec();
         if(spec.isEntity()) {
             if(MmEntityUtils.getEntityState(adapter).isTransientOrRemoved()) {
                 return false;
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_Compliance.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_Compliance.java
new file mode 100644
index 00000000000..e58e35aaad1
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_Compliance.java
@@ -0,0 +1,113 @@
+/*
+ *  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.causeway.core.metamodel.object;
+
+import java.util.Objects;
+
+import org.jspecify.annotations.NonNull;
+
+import org.apache.causeway.applib.services.bookmark.Bookmark;
+import org.apache.causeway.commons.internal.assertions._Assert;
+import org.apache.causeway.commons.internal.exceptions._Exceptions;
+import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
+
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+class _Compliance {
+
+    <T> T assertCompliance(
+        final ObjectSpecification objSpec,
+        final ManagedObject.Specialization specialization,
+        final @NonNull T pojo) {
+
+        MmAssertionUtils.assertPojoNotWrapped(pojo);
+        if(objSpec.isAbstract()) {
+            _Assert.assertFalse(specialization.getTypePolicy().isExactTypeRequired(),
+                    ()->String.format("Specialization %s does not allow abstract type %s",
+                            specialization,
+                            objSpec));
+        }
+        if(specialization.getTypePolicy().isExactTypeRequired()) {
+            MmAssertionUtils.assertExactType(objSpec, pojo);
+        }
+        if(specialization.getInjectionPolicy().isAlwaysInject()) {
+            var isInjectionPointsResolved = objSpec.entityFacet()
+                .map(entityFacet->entityFacet.isInjectionPointsResolved(pojo))
+                .orElse(false);
+            if(!isInjectionPointsResolved) {
+                objSpec.getServiceInjector().injectServicesInto(pojo); // might be redundant
+            }
+        }
+        return pojo;
+    }
+
+    boolean equals(final ManagedObject mo, final Object obj) {
+        if(mo == obj) return true;
+        if(!(obj instanceof ManagedObject)) return false;
+
+        var other = (ManagedObject)obj;
+        if(!mo.specialization().equals(other.specialization())) return false;
+        if(!mo.objSpec().equals(other.objSpec())) return false;
+
+        var canGetPojosWithoutSideeffect = !mo.specialization().getPojoPolicy().isRefetchable();
+        if(canGetPojosWithoutSideeffect) {
+            // expected to work for packed variant just fine, as it compares lists
+            return Objects.equals(mo.getPojo(), other.getPojo());
+        }
+
+        if(mo.isBookmarkMemoized()
+                && other.isBookmarkMemoized()) {
+            return Objects.equals(
+                    sideEffectFreeBookmark(mo),
+                    other.getBookmark().orElseThrow(_Exceptions::unexpectedCodeReach));
+        }
+
+        var a = (_Refetchable) mo;
+        var b = (_Refetchable) mo;
+        return Objects.equals(a.peekAtPojo(), b.peekAtPojo());
+    }
+
+    int hashCode(final ManagedObject mo) {
+        // make sure hashCode() is without side-effects!
+        var canGetPojosWithoutSideeffect = !mo.specialization().getPojoPolicy().isRefetchable();
+        return canGetPojosWithoutSideeffect
+                // expected to work for packed variant just fine, as it compares lists
+                ? Objects.hash(mo.objSpec().getCorrespondingClass(), mo.getPojo())
+                : Objects.hash(mo.objSpec().getCorrespondingClass(), sideEffectFreeBookmark(mo));
+    }
+
+    String toString(final ManagedObject mo) {
+        // make sure toString() is without side-effects!
+        return String.format("ManagedObject(%s, spec=%s, pojo=%s)",
+            mo.specialization().name(),
+            mo.objSpec(),
+            !mo.specialization().getPojoPolicy().isRefetchable()
+                ? mo.getPojo() // its safe to get pojo side-effect free
+                : mo.isBookmarkMemoized()
+                    ? String.format("(refetchable, %s)", sideEffectFreeBookmark(mo))
+                    : "(refetchable, suppressed to not cause side effects)");
+    }
+
+    private Bookmark sideEffectFreeBookmark(final ManagedObject mo) {
+        _Assert.assertTrue(mo.isBookmarkMemoized());
+        return mo.getBookmark().orElseThrow(_Exceptions::unexpectedCodeReach);
+    }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_InternalTitleUtil.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_InternalTitleUtil.java
index 7b2280795d6..f5bd03d591b 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_InternalTitleUtil.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_InternalTitleUtil.java
@@ -37,9 +37,9 @@ String titleString(final @NonNull TitleRenderRequest titleRenderRequest) {
 
         var managedObject = titleRenderRequest.object();
 
-        if(managedObject.getSpecialization().isUnspecified()) return managedObject.getTitle();
+        if(managedObject.specialization().isUnspecified()) return managedObject.getTitle();
 
-        var objSpec = managedObject.getSpecification();
+        var objSpec = managedObject.objSpec();
 
         return objSpec.isSingular()
             ? objectTitleString(titleRenderRequest)
@@ -61,13 +61,13 @@ private String objectTitleString(final @NonNull TitleRenderRequest titleRenderRe
         //TODO we have value-semantics now, don't skip it for strings
         if (managedObject.getPojo() instanceof String) return (String) managedObject.getPojo();
 
-        var spec = managedObject.getSpecification();
+        var spec = managedObject.objSpec();
         return Optional.ofNullable(spec.getTitle(titleRenderRequest))
                 .orElseGet(()->getDefaultTitle(managedObject));
     }
 
     private String getDefaultTitle(final ManagedObject managedObject) {
-        return "A" + (" " + managedObject.getSpecification().getSingularName()).toLowerCase();
+        return "A" + (" " + managedObject.objSpec().getSingularName()).toLowerCase();
     }
 
     private String formatAnyCardinalityAsTitle(final @NonNull ObjectSpecification objSpec, final @NonNull ManagedObject managedObject) {
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEmpty.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEmpty.java
index e862be0689e..cb249fab13d 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEmpty.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEmpty.java
@@ -40,7 +40,7 @@ public Object getPojo() {
 
     @Override
     public String getTitle() {
-        return "empty " + getSpecification().logicalTypeName();
+        return "empty " + objSpec().logicalTypeName();
     }
 
 }
\ No newline at end of file
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEntityBookmarked.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEntityBookmarked.java
index 61c4c395d86..1cef0373f6d 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEntityBookmarked.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEntityBookmarked.java
@@ -83,7 +83,7 @@ public Object getPojo() {
 
         var entityState = entityFacet.getEntityState(pojo);
         if(!entityState.isPersistable()) {
-            throw _Exceptions.illegalState("not persistable %s", getSpecification());
+            throw _Exceptions.illegalState("not persistable %s", objSpec());
         }
         if(entityState.isAttached()) {
             return pojo; // is attached
@@ -134,13 +134,13 @@ private Object refetchPojo(final EntityState entityState) {
             throw new ObjectNotFoundException("" + bookmark);
         }
 
-        _XrayEvent.event("Entity %s refetched from persistence.", getSpecification());
+        _XrayEvent.event("Entity %s refetched from persistence.", objSpec());
 
         return refetchedPojo;
     }
 
     private EntityFacet entityFacet() {
-        return getSpecification().entityFacetElseFail();
+        return objSpec().entityFacetElseFail();
     }
 
     @SuppressWarnings("deprecation")
@@ -163,7 +163,7 @@ private Bookmark createBookmark() {
                     "The persistence layer does not recognize given object %s, "
                     + "meaning the object has no identifier that associates it with the persistence layer. "
                     + "(most likely, because the object is detached, eg. was not persisted after being new-ed up)",
-                    getSpecification());
+                    objSpec());
 
             // in case of the exception getting swallowed, also write a log
             log.error(msg);
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEntityHybrid.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEntityHybrid.java
index 6af30f34125..41449775aae 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEntityHybrid.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEntityHybrid.java
@@ -75,14 +75,14 @@ static MorphState valueOf(final EntityState entityState) {
 
     _ManagedObjectEntityHybrid(
             final @NonNull _ManagedObjectEntityTransient _transient) {
-        super(ManagedObject.Specialization.ENTITY, _transient.getSpecification());
+        super(ManagedObject.Specialization.ENTITY, _transient.objSpec());
         this.variant = _transient;
         this.morphState = MorphState.TRANSIENT;
     }
 
     _ManagedObjectEntityHybrid(
             final @NonNull _ManagedObjectEntityBookmarked bookmarked) {
-        super(ManagedObject.Specialization.ENTITY, bookmarked.getSpecification());
+        super(ManagedObject.Specialization.ENTITY, bookmarked.objSpec());
         this.variant = bookmarked;
         this.morphState = MorphState.BOOKMARKED;
         _Assert.assertTrue(bookmarked.getBookmark().isPresent(),
@@ -92,14 +92,14 @@ static MorphState valueOf(final EntityState entityState) {
     @Override
     public Optional<Bookmark> getBookmark() {
         return (variant instanceof Bookmarkable)
-                ? ((Bookmarkable)variant).getBookmark()
+                ? variant.getBookmark()
                 : Optional.empty();
     }
 
     @Override
     public boolean isBookmarkMemoized() {
         return (variant instanceof Bookmarkable)
-                ? ((Bookmarkable)variant).isBookmarkMemoized()
+                ? variant.isBookmarkMemoized()
                 : false;
     }
 
@@ -148,14 +148,6 @@ public Object peekAtPojo() {
                 : null;
     }
 
-    @Override
-    protected boolean isInjectionPointsResolved() {
-        // overriding the default for optimization, let the EntityFacet handle injection
-        // as a side-effect potentially injects if required
-        return getSpecification().entityFacetElseFail()
-                .isInjectionPointsResolved(peekAtPojo());
-    }
-
     // -- HELPER
 
     private void triggerReassessment() {
@@ -197,7 +189,7 @@ private void reassessVariant(final EntityState entityState, final Object pojo) {
 
     // morph into attached
     private void makeBookmarked(final Object pojo) {
-        var attached = new _ManagedObjectEntityBookmarked(getSpecification(), pojo, Optional.empty());
+        var attached = new _ManagedObjectEntityBookmarked(objSpec(), pojo, Optional.empty());
         this.variant = attached;
         _Assert.assertTrue(attached.getBookmark().isPresent(),
                 ()->"bookmarked entity must have bookmark");
@@ -205,7 +197,7 @@ private void makeBookmarked(final Object pojo) {
 
     // morph into attached
     private void makeRemoved() {
-        var removed = new _ManagedObjectEntityRemoved(getSpecification());
+        var removed = new _ManagedObjectEntityRemoved(objSpec());
         this.variant = removed;
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEntityTransient.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEntityTransient.java
index 8f43aadcf66..725248f7256 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEntityTransient.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectEntityTransient.java
@@ -66,7 +66,7 @@ public Object peekAtPojo() {
     // -- HELPER
 
     private EntityFacet entityFacet() {
-        return getSpecification().entityFacetElseFail();
+        return objSpec().entityFacetElseFail();
     }
 
 }
\ No newline at end of file
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectSpecified.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectSpecified.java
index d2350530ebd..9a4b7df59f9 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectSpecified.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectSpecified.java
@@ -19,23 +19,18 @@
 package org.apache.causeway.core.metamodel.object;
 
 import java.util.ArrayList;
-import java.util.Objects;
 import java.util.Optional;
-import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
+import org.jspecify.annotations.NonNull;
 import org.jspecify.annotations.Nullable;
 
-import org.apache.causeway.applib.services.bookmark.Bookmark;
-import org.apache.causeway.commons.internal.assertions._Assert;
-import org.apache.causeway.commons.internal.exceptions._Exceptions;
 import org.apache.causeway.core.metamodel.facets.object.title.TitleRenderRequest;
 import org.apache.causeway.core.metamodel.objectmanager.memento.ObjectMemento;
 import org.apache.causeway.core.metamodel.spec.ObjectSpecification;
 
 import lombok.AccessLevel;
 import lombok.Getter;
-import org.jspecify.annotations.NonNull;
 import lombok.RequiredArgsConstructor;
 import lombok.experimental.Accessors;
 
@@ -43,43 +38,17 @@
 abstract class _ManagedObjectSpecified
 implements ManagedObject {
 
-    @Getter(onMethod_ = {@Override}) @Accessors(makeFinal = true)
+    @Getter(onMethod_ = {@Override}) @Accessors(fluent = true, makeFinal = true)
     private final @NonNull Specialization specialization;
 
-    @Getter(onMethod_ = {@Override}) @Accessors(makeFinal = true)
-    private final @NonNull ObjectSpecification specification;
-
-    @Override
-    public final Supplier<ManagedObject> asSupplier() {
-        return ()->this;
-    }
+    @Getter(onMethod_ = {@Override}) @Accessors(fluent = true, makeFinal = true)
+    private final @NonNull ObjectSpecification objSpec;
 
     @Override
     public final <T> T assertCompliance(final @NonNull T pojo) {
-        MmAssertionUtils.assertPojoNotWrapped(pojo);
-        if(specification.isAbstract()) {
-            _Assert.assertFalse(specialization.getTypePolicy().isExactTypeRequired(),
-                    ()->String.format("Specialization %s does not allow abstract type %s",
-                            specialization,
-                            specification));
-        }
-        if(specialization.getTypePolicy().isExactTypeRequired()) {
-            MmAssertionUtils.assertExactType(specification, pojo);
-        }
-        if(getSpecialization().getInjectionPolicy().isAlwaysInject()) {
-            if(!isInjectionPointsResolved()) {
-                getServiceInjector().injectServicesInto(pojo); // might be redundant
-            }
-        }
-        return pojo;
+        return _Compliance.assertCompliance(objSpec, specialization, pojo);
     }
 
-    /**
-     * override if there is optimization available
-     * @apiNote must only be called by {@link #assertCompliance(Object)}
-     */
-    protected boolean isInjectionPointsResolved() { return false; }
-
     @Override
     public String getTitle() {
         return _InternalTitleUtil.titleString(
@@ -98,7 +67,7 @@ private ObjectMemento mementoForScalar(final @Nullable ManagedObject adapter) {
         return ObjectMemento.singular(adapter)
                 .orElseGet(()->
                     ManagedObjects.isSpecified(adapter)
-                        ? ObjectMemento.empty(adapter.getLogicalType())
+                        ? ObjectMemento.empty(adapter.logicalType())
                         : null);
     }
 
@@ -107,74 +76,23 @@ private ObjectMemento mementoForPacked(final @NonNull PackedManagedObject packed
                 .map(this::mementoForScalar)
                 .collect(Collectors.toCollection(ArrayList::new)); // ArrayList is serializable
         return ObjectMemento.packed(
-                packedAdapter.getLogicalType(),
+                packedAdapter.logicalType(),
                 listOfMementos);
     }
 
-    //XXX compares pojos by their 'equals' semantics -
-    // note though: some value-types have an explicit order-relation which could potentially say differently
     @Override
     public final boolean equals(final Object obj) {
-        // make sure equals(Object) is without side-effects!
-        if(this == obj) {
-            return true;
-        }
-        if(!(obj instanceof ManagedObject)) {
-            return false;
-        }
-        var other = (ManagedObject)obj;
-        if(!this.getSpecialization().equals(other.getSpecialization())) {
-            return false;
-        }
-        if(!this.getSpecification().equals(other.getSpecification())) {
-            return false;
-        }
-        var canGetPojosWithoutSideeffect = !getSpecialization().getPojoPolicy().isRefetchable();
-        if(canGetPojosWithoutSideeffect) {
-            // expected to work for packed variant just fine, as it compares lists
-            return Objects.equals(this.getPojo(), other.getPojo());
-        }
-
-        if(this.isBookmarkMemoized()
-                && other.isBookmarkMemoized()) {
-            return Objects.equals(
-                    sideEffectFreeBookmark(),
-                    other.getBookmark().orElseThrow(_Exceptions::unexpectedCodeReach));
-        }
-
-        var a = (_Refetchable) this;
-        var b = (_Refetchable) this;
-        return Objects.equals(a.peekAtPojo(), b.peekAtPojo());
+        return _Compliance.equals(this, obj);
     }
 
     @Override
     public final int hashCode() {
-        // make sure hashCode() is without side-effects!
-        var canGetPojosWithoutSideeffect = !getSpecialization().getPojoPolicy().isRefetchable();
-        return canGetPojosWithoutSideeffect
-                // expected to work for packed variant just fine, as it compares lists
-                ? Objects.hash(getSpecification().getCorrespondingClass(), getPojo())
-                : Objects.hash(getSpecification().getCorrespondingClass(), sideEffectFreeBookmark());
+        return _Compliance.hashCode(this);
     }
 
     @Override
     public final String toString() {
-        // make sure toString() is without side-effects!
-        return String.format("ManagedObject(%s, spec=%s, pojo=%s)",
-                getSpecialization().name(),
-                getSpecification(),
-                !getSpecialization().getPojoPolicy().isRefetchable()
-                    ? getPojo() // its safe to get pojo side-effect free
-                    : isBookmarkMemoized()
-                        ? String.format("(refetchable, %s)", sideEffectFreeBookmark())
-                        : "(refetchable, suppressed to not cause side effects)");
-    }
-
-    // -- HELPER
-
-    private Bookmark sideEffectFreeBookmark() {
-        _Assert.assertTrue(isBookmarkMemoized());
-        return getBookmark().orElseThrow(_Exceptions::unexpectedCodeReach);
+        return _Compliance.toString(this);
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectValue.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectValue.java
index ea55a225f1d..941ac4c2e4a 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectValue.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectValue.java
@@ -66,7 +66,7 @@ public boolean isBookmarkMemoized() {
     // -- HELPER
 
     private ValueFacet<?> valueFacet() {
-        return getSpecification().valueFacetElseFail();
+        return objSpec().valueFacetElseFail();
     }
 
     private Bookmark createBookmark() {
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectViewmodel.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectViewmodel.java
index 5f85fd9f3d4..d51b321641f 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectViewmodel.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/object/_ManagedObjectViewmodel.java
@@ -87,7 +87,7 @@ private void replaceBookmark(final UnaryOperator<Bookmark> replacer) {
     }
 
     private Optional<Bookmark> createBookmark() {
-        return Optional.ofNullable(getSpecification().viewmodelFacetElseFail().serializeToBookmark(this));
+        return Optional.ofNullable(objSpec().viewmodelFacetElseFail().serializeToBookmark(this));
     }
 
     // -- REFRESH OPTIMIZATION
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/ObjectCreatorFactory.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/ObjectCreatorFactory.java
index 7743714be2e..609a9648b85 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/ObjectCreatorFactory.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/ObjectCreatorFactory.java
@@ -73,10 +73,10 @@ public ManagedObject handle(final ObjectSpecification spec) {
             var domainObject = ManagedObject.adaptSingular(spec, pojo);
 
             // initialize new object
-            domainObject.getSpecification().streamAssociations(MixedIn.EXCLUDED)
+            domainObject.objSpec().streamAssociations(MixedIn.EXCLUDED)
                 .forEach(field->field.toDefault(domainObject));
 
-            if (domainObject.getSpecification().isEntity()) {
+            if (domainObject.objSpec().isEntity()) {
                 persistenceLifecyclePublisher().get().onPostCreate(domainObject);
             }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/ObjectManager.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/ObjectManager.java
index 4c0ae5ed276..bc2bd26ef3d 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/ObjectManager.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/ObjectManager.java
@@ -128,7 +128,7 @@ public Optional<ManagedObject> loadObject(final @Nullable Bookmark bookmark) {
      */
     public Bookmark bookmark(final @NonNull ManagedObject managedObj) {
         return ManagedObjects.bookmark(managedObj)
-                .orElseGet(()->Bookmark.empty(managedObj.getLogicalType()));
+                .orElseGet(()->Bookmark.empty(managedObj.logicalType()));
     }
     /**
      * Introduced for de-serializing action parameter values from bookmarks and vice versa.
@@ -148,7 +148,7 @@ public ManagedObject debookmark(final @NonNull Bookmark bookmark) {
     public ManagedObject loadObjectElseFail(final @NonNull Bookmark bookmark) {
         var adapter = loadObject(bookmark)
                 .orElseThrow(() -> new BookmarkNotFoundException(String.format("Bookmark %s was not found.", bookmark)));
-        if(adapter.getSpecialization().isEntity()) {
+        if(adapter.specialization().isEntity()) {
             _Assert.assertEquals(bookmark, adapter.getBookmark().orElse(null),
                     ()->"object loaded from bookmark must itself return an equal bookmark");
         }
@@ -238,7 +238,7 @@ public Optional<ObjectMemento> mementify(final @Nullable ManagedObject object) {
     public ObjectMemento mementifyElseFail(final @NonNull ManagedObject object) {
         return object.getMemento()
                 .orElseThrow(()->
-                    _Exceptions.unrecoverable("failed to create memento for  %s", object.getSpecification()));
+                    _Exceptions.unrecoverable("failed to create memento for  %s", object.objSpec()));
     }
 
     public ManagedObject demementify(final @Nullable ObjectMemento memento) {
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoSingular.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoSingular.java
index cf7feaa837a..8cf9f03b4a7 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoSingular.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/objectmanager/memento/ObjectMementoSingular.java
@@ -36,7 +36,7 @@ record ObjectMementoSingular(
     // -- FACTORIES
 
     static ObjectMementoSingular create(final @NonNull ManagedObject adapter) {
-        var spec = adapter.getSpecification();
+        var spec = adapter.objSpec();
 
         _Assert.assertTrue(spec.isIdentifiable()
                 || spec.isParented()
@@ -49,7 +49,7 @@ static ObjectMementoSingular create(final @NonNull ManagedObject adapter) {
                         .formatted(spec));
 
         return new ObjectMementoSingular(
-                adapter.getLogicalType(),
+                adapter.logicalType(),
                 MmHintUtils.bookmarkElseFail(adapter),
                 MmTitleUtils.titleOf(adapter));
     }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/postprocessors/allbutparam/authorization/AuthorizationFacetAbstract.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/postprocessors/allbutparam/authorization/AuthorizationFacetAbstract.java
index 7f7a6ec8707..9ec008cec58 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/postprocessors/allbutparam/authorization/AuthorizationFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/postprocessors/allbutparam/authorization/AuthorizationFacetAbstract.java
@@ -50,7 +50,7 @@ public AuthorizationFacetAbstract(
     @Override
     public String hides(final VisibilityContext ic) {
 
-        if(ic.head().owner().getSpecification().isValue()) {
+        if(ic.head().owner().objSpec().isValue()) {
             return null; // never hide value-types
         }
 
@@ -71,7 +71,7 @@ public String hides(final VisibilityContext ic) {
     @Override
     public Optional<VetoReason> disables(final UsabilityContext ic) {
 
-        if(ic.head().owner().getSpecification().isValue()) {
+        if(ic.head().owner().objSpec().isValue()) {
             return Optional.empty(); // never disable value-types
         }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/title/TitleServiceDefault.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/title/TitleServiceDefault.java
index 5f5be4fb000..2df81541a93 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/title/TitleServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/services/title/TitleServiceDefault.java
@@ -64,7 +64,7 @@ public String titleOf(final Object domainObject) {
         return MmEntityUtils.getEntityState(objectAdapter).isTransientOrRemoved()
             // here we just mean NOT-ATTACHED (and not the concrete DETACHED entity state)
             ? "[DETACHED]"
-            : objectAdapter.getSpecification().getTitle(TitleRenderRequest.forObject(objectAdapter));
+            : objectAdapter.objSpec().getTitle(TitleRenderRequest.forObject(objectAdapter));
     }
 
     @Override
@@ -78,7 +78,7 @@ public String iconNameOf(final Object domainObject) {
 
         return ManagedObjects.isNullOrUnspecifiedOrEmpty(objectAdapter)
             ? "unspecified"
-            : objectAdapter.getSpecification().getIconName(objectAdapter);
+            : objectAdapter.objSpec().getIconName(objectAdapter);
     }
 
     //-- HELPER
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/HasObjectSpecification.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/HasObjectSpecification.java
index ccb231e6c0d..d4939f3c4f4 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/HasObjectSpecification.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/HasObjectSpecification.java
@@ -20,41 +20,43 @@
 
 import java.util.Optional;
 
+import org.jspecify.annotations.NonNull;
+
 import org.apache.causeway.applib.id.LogicalType;
 import org.apache.causeway.applib.services.bookmark.Bookmark;
 
-import org.jspecify.annotations.NonNull;
-
 /**
  * Introduced as a shortcut provider.
  */
 public interface HasObjectSpecification {
 
-    ObjectSpecification getSpecification();
+    @Deprecated default ObjectSpecification getSpecification() { return objSpec(); }
+
+    ObjectSpecification objSpec();
 
     // -- SHORTCUTS
 
     default Class<?> getCorrespondingClass() {
-        return getSpecification().getCorrespondingClass();
+        return objSpec().getCorrespondingClass();
     }
 
-    default LogicalType getLogicalType() {
-        return getSpecification().logicalType();
+    default LogicalType logicalType() {
+        return objSpec().logicalType();
     }
 
-    default String getLogicalTypeName() {
-        return getSpecification().logicalTypeName();
+    default String logicalTypeName() {
+        return objSpec().logicalTypeName();
     }
 
     /**
      * As used for the element type of collections.
      */
     default Optional<ObjectSpecification> getElementSpecification() {
-        return getSpecification().getElementSpecification();
+        return objSpec().getElementSpecification();
     }
 
     default Bookmark createBookmark(final @NonNull String urlSafeIdentifier) {
-        return Bookmark.forLogicalTypeAndIdentifier(getLogicalType(), urlSafeIdentifier);
+        return Bookmark.forLogicalTypeAndIdentifier(logicalType(), urlSafeIdentifier);
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAction.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAction.java
index 865dcbd5aca..8c4b50f0f53 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAction.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectAction.java
@@ -368,7 +368,7 @@ public static Optional<FaLayersProvider> cssClassFaFactoryFor(
         public static Stream<ObjectAction> streamTopBarActions(
                 final ManagedObject adapter) {
 
-            var spec = adapter.getSpecification();
+            var spec = adapter.objSpec();
 
             return spec.streamRuntimeActions(MixedIn.INCLUDED)
             .filter(Predicates
@@ -382,7 +382,7 @@ public static Stream<ObjectAction> findForAssociation(
                 final ManagedObject adapter,
                 final ObjectAssociation association) {
 
-            var spec = adapter.getSpecification();
+            var spec = adapter.objSpec();
 
             return spec.streamRuntimeActions(MixedIn.INCLUDED)
             .filter(Predicates.isSameLayoutGroupAs(association))
@@ -411,9 +411,9 @@ public static String friendlyNameFor(
 
             if(mixeeAdapter != null) {
                 var mixinSpec = action.getDeclaringType();
-                var ownerSpec = mixeeAdapter.getSpecification();
+                var ownerSpec = mixeeAdapter.objSpec();
                 return ownerSpec.lookupMixedInMember(mixinSpec)
-                        .map(mixedInMember->mixedInMember.getFriendlyName(mixeeAdapter.asSupplier()))
+                        .map(mixedInMember->mixedInMember.getFriendlyName(mixeeAdapter))
                         .orElseThrow(_Exceptions::unexpectedCodeReach);
             }
             return action.getFriendlyName(head::owner);
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectFeature.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectFeature.java
index d08fc9a8f8d..675e7fe8440 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectFeature.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/feature/ObjectFeature.java
@@ -60,6 +60,10 @@ public interface ObjectFeature extends Specification {
      * @see #getFeatureIdentifier()
      */
     String getFriendlyName(Supplier<ManagedObject> domainObjectProvider);
+    default String getFriendlyName(final ManagedObject domainObject) {
+        return getFriendlyName(()->domainObject);
+    }
+
 
     /**
      * Optionally returns the (translated friendly) name for this member -
@@ -107,6 +111,9 @@ default Either<String, String> getStaticOrCanonicalFriendlyName() {
      *
      */
     Optional<String> getDescription(final Supplier<ManagedObject> domainObjectProvider);
+    default Optional<String> getDescription(final ManagedObject domainObject) {
+        return getDescription(()->domainObject);
+    }
 
     /**
      * Optionally returns the (translated) description of how the member is used,
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/ObjectActionDefault.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/ObjectActionDefault.java
index 5b29185cb01..e1b9f0c716d 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/ObjectActionDefault.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/ObjectActionDefault.java
@@ -532,7 +532,7 @@ public void setupCommand(
             final InteractionHead head,
             final Can<ManagedObject> argumentAdapters) {
 
-        if(head.owner().getSpecification().isValue()) {
+        if(head.owner().objSpec().isValue()) {
             return; // do not record value type mixin actions
         }
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/ObjectActionMixedIn.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/ObjectActionMixedIn.java
index 7acb87a40a4..b80fd26ee62 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/ObjectActionMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/ObjectActionMixedIn.java
@@ -158,7 +158,7 @@ public ManagedObject execute(
 
         final ManagedObject owner = head.owner();
         final ManagedObject target = mixinAdapterFor(mixinSpec, owner);
-        _Assert.assertEquals(target.getSpecification(), head.target().getSpecification(),
+        _Assert.assertEquals(target.objSpec(), head.target().objSpec(),
                 "head has the wrong target (should be a mixed-in adapter, but is the mixee adapter)");
 
         if(!interactionInitiatedBy.isPassThrough()) {
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/ObjectSpecificationDefault.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/ObjectSpecificationDefault.java
index 7bc2a8a7c3d..de481856a73 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/ObjectSpecificationDefault.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/ObjectSpecificationDefault.java
@@ -770,7 +770,7 @@ private void notifySubscribersIfEntity(
     @Override
     public String getIconName(final ManagedObject domainObject) {
         if(ManagedObjects.isSpecified(domainObject)) {
-            _Assert.assertEquals(domainObject.getSpecification(), this);
+            _Assert.assertEquals(domainObject.objSpec(), this);
         }
         return iconFacet != null
                 ? iconFacet.iconName(domainObject)
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/_MembersAsColumns.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/_MembersAsColumns.java
index 4e084f08cfc..e574c9882c8 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/_MembersAsColumns.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/spec/impl/_MembersAsColumns.java
@@ -73,7 +73,7 @@ public final Stream<ObjectAssociation> streamAssociationsForColumnRendering(
         // the type that has the properties and collections that make up this table's columns
         var elementClass = elementType.getCorrespondingClass();
 
-        var parentSpecIfAny = parentObject.getSpecification();
+        var parentSpecIfAny = parentObject.objSpec();
 
         var assocById = _Maps.<String, ObjectAssociation>newLinkedHashMap();
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/internal/DataTableInternal.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/internal/DataTableInternal.java
index d9647345a0c..903eb0b611a 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/internal/DataTableInternal.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/tabular/internal/DataTableInternal.java
@@ -453,7 +453,7 @@ public DataTableInternal getDataTableModel(final ManagedObject owner) {
             var dataTableInteractive = new DataTableInternal(managedMember, where,
                     dataTable.streamDataElements()
                     .peek(obj->{
-                        if(obj.getSpecialization().isViewmodel()) {
+                        if(obj.specialization().isViewmodel()) {
                             // make sure any referenced entities are made live if currently hollow
                             ManagedObjects.refreshViewmodel(obj, /*bookmark supplier*/ null);
                         }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/Facets.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/Facets.java
index b2b9d9dcd2e..10b800ad103 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/Facets.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/Facets.java
@@ -314,7 +314,7 @@ public OptionalInt multilineNumberOfLines(final ObjectFeature feature) {
 
     //XXX could be moved to ManagedObject directly
     public ManagedObject projected(final ManagedObject objectAdapter) {
-        return objectAdapter.getSpecification().lookupFacet(ProjectionFacet.class)
+        return objectAdapter.objSpec().lookupFacet(ProjectionFacet.class)
             .map(projectionFacet->projectionFacet.projected(objectAdapter))
             .orElse(objectAdapter);
     }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/snapshot/XmlSnapshot.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/snapshot/XmlSnapshot.java
index cfb6c87f2a3..33d33f6204a 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/snapshot/XmlSnapshot.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/util/snapshot/XmlSnapshot.java
@@ -206,7 +206,7 @@ private Place appendXml(final ManagedObject object) {
             log.debug("appendXml({})", log("obj", object));
         }
 
-        final String fullyQualifiedClassName = object.getSpecification().getFullIdentifier();
+        final String fullyQualifiedClassName = object.objSpec().getFullIdentifier();
 
         schema.setUri(fullyQualifiedClassName); // derive URI from fully qualified name
 
@@ -446,7 +446,7 @@ private boolean includeField(final Place place, final Vector<String> fieldNames,
         }
 
         // locate the field in the object's class
-        final ObjectSpecification nos = object.getSpecification();
+        final ObjectSpecification nos = object.objSpec();
         // HACK: really want a ObjectSpecification.hasField method to
         // check first.
         var field = nos.getAssociation(fieldName).orElse(null);
@@ -628,7 +628,7 @@ Place objectToElement(final ManagedObject adapter) {
             log.debug("objectToElement({})", log("object", adapter));
         }
 
-        final ObjectSpecification spec = adapter.getSpecification();
+        final ObjectSpecification spec = adapter.objSpec();
 
         if (log.isDebugEnabled()) {
             log.debug("objectToElement(NO): create element and causeway:title");
@@ -666,7 +666,7 @@ Place objectToElement(final ManagedObject adapter) {
 
             // Skip field if we have seen the name already
             for (int j = 0; j < i; j++) {
-                if (Objects.equals(fieldName, fields.get(i).getFriendlyName(adapter.asSupplier()))) {
+                if (Objects.equals(fieldName, fields.get(i).getFriendlyName(adapter))) {
                     log.debug("objectToElement(NO): {} SKIPPED", log("field", fieldName));
                     continue eachField;
                 }
@@ -702,7 +702,7 @@ Place objectToElement(final ManagedObject adapter) {
                 try {
                     value = valueAssociation.get(adapter, InteractionInitiatedBy.PASS_THROUGH);
 
-                    var valueSpec = value.getSpecification();
+                    var valueSpec = value.objSpec();
 
                     // XML
                     causewayMetaModel.setAttributesForValue(xmlValueElement, valueSpec.getShortIdentifier());
diff --git a/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactoryTest.java
index a4270b6c75e..ada40f21374 100644
--- a/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactoryTest.java
@@ -92,7 +92,7 @@ void viewModelInterfacePickedUpOnClassAndDefaultsToAlways() {
                 var customerBookmark = viewModelFacet.serializeToBookmark(customer);
 
                 var customerRecreated = viewModelFacet.instantiate(
-                        customer.getSpecification(), Optional.of(customerBookmark));
+                        customer.objSpec(), Optional.of(customerBookmark));
 
                 assertEquals(customerPojo.getName(), ((Customer)(customerRecreated.getPojo())).getName());
             }
diff --git a/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/object/ManagedObjectTest.java b/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/object/ManagedObjectTest.java
index 87450e65a74..75c4fe213fa 100644
--- a/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/object/ManagedObjectTest.java
+++ b/core/metamodel/src/test/java/org/apache/causeway/core/metamodel/object/ManagedObjectTest.java
@@ -89,7 +89,7 @@ void intShouldMapToValue(final Class<?> cls) {
         assertNotNull(emptyObject);
 
         var presentObject = ManagedObject.adaptSingular(specLoader, 3);
-        assertEquals(Specialization.VALUE, presentObject.getSpecialization());
+        assertEquals(Specialization.VALUE, presentObject.specialization());
 
         presentObject.assertCompliance(6);
 
@@ -118,7 +118,7 @@ void someTypesShouldMapToViewmodel(final Class<?> cls) {
         var pojo = constructor.newInstance(_Constants.emptyObjects);
 
         var presentObject = ManagedObject.adaptSingular(specLoader, pojo);
-        assertEquals(Specialization.VIEWMODEL, presentObject.getSpecialization());
+        assertEquals(Specialization.VIEWMODEL, presentObject.specialization());
 
         presentObject.assertCompliance(pojo);
 
diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/command/CommandExecutorServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/command/CommandExecutorServiceDefault.java
index de2a2da088e..a6038bc5587 100644
--- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/command/CommandExecutorServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/command/CommandExecutorServiceDefault.java
@@ -266,7 +266,7 @@ private static ObjectAction findObjectAction(
             final ManagedObject targetAdapter,
             final String logicalMemberIdentifier) throws RuntimeException {
 
-        var objectSpecification = targetAdapter.getSpecification();
+        var objectSpecification = targetAdapter.objSpec();
 
         // we use the local identifier because the fullyQualified version includes the class name.
         // that is a problem for us if the property is inherited, because it will be the class name of the declaring
@@ -289,7 +289,7 @@ private static OneToOneAssociation findOneToOneAssociation(
         // superclass, rather than the concrete class of the target that we are inspecting here.
         var localPropertyId = localPartOf(logicalMemberIdentifier);
 
-        var objectSpecification = targetAdapter.getSpecification();
+        var objectSpecification = targetAdapter.objSpec();
 
         var property = findOneToOneAssociationElseNull(objectSpecification, localPropertyId);
         if(property == null) {
diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/command/SchemaValueMarshallerDefault.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/command/SchemaValueMarshallerDefault.java
index f39ed9d2150..85c8c1f7086 100644
--- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/command/SchemaValueMarshallerDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/command/SchemaValueMarshallerDefault.java
@@ -72,7 +72,7 @@ protected <T> ValueWithTypeDto recordValue(
             final ManagedObject value) {
 
         valueDto.setType(context.schemaValueType());
-        if (value.getSpecialization().isEmpty()) {
+        if (value.specialization().isEmpty()) {
             valueDto.setNull(true);
         }
 
diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/executor/MemberExecutorServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/executor/MemberExecutorServiceDefault.java
index 7981eb645d5..070830492b7 100644
--- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/executor/MemberExecutorServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/executor/MemberExecutorServiceDefault.java
@@ -183,7 +183,7 @@ private ManagedObject invokeActionInternally(
 
         // assert has bookmark, unless non-scalar
         ManagedObjects.asScalarNonEmpty(returnedAdapter)
-        .filter(scalarNonEmpty->!scalarNonEmpty.getSpecialization().isOther()) // don't care
+        .filter(scalarNonEmpty->!scalarNonEmpty.specialization().isOther()) // don't care
         // if its a transient entity, flush the current transaction, so we get an OID
         .filter(scalarNonEmpty->{
             MmEntityUtils.ifHasNoOidThenFlush(scalarNonEmpty);
@@ -191,7 +191,7 @@ private ManagedObject invokeActionInternally(
         })
         .ifPresent(scalarNonEmpty->{
             _Assert.assertTrue(scalarNonEmpty.getBookmark().isPresent(), ()->{
-                var returnTypeSpec = scalarNonEmpty.getSpecification();
+                var returnTypeSpec = scalarNonEmpty.objSpec();
                 var violation = returnTypeSpec.isEntity()
                         ? MessageTemplate.ACTION_METHOD_RETURNING_TRANSIENT_ENTITY_NOT_ALLOWED
                         : MessageTemplate.ACTION_METHOD_RETURNING_NON_BOOKMARKABLE_OBJECT_NOT_ALLOWED;
diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/menubars/bootstrap/MenuBarsServiceBootstrap.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/menubars/bootstrap/MenuBarsServiceBootstrap.java
index 04ceb03c848..e572bfa2d3a 100644
--- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/menubars/bootstrap/MenuBarsServiceBootstrap.java
+++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/menubars/bootstrap/MenuBarsServiceBootstrap.java
@@ -186,7 +186,7 @@ private BSMenuBars updateFacetsFromActionLayoutXml(final BSMenuBars menuBarsFrom
         .filter(this::isVisibleAdapterForMenu)
         .forEach(serviceAdapter->{
 
-            var serviceSpec = serviceAdapter.getSpecification();
+            var serviceSpec = serviceAdapter.objSpec();
 
             serviceSpec.streamAnyActions(MixedIn.INCLUDED)
             .forEach(objectAction->{
@@ -287,7 +287,7 @@ private BSMenuBars menuBarsFromAnnotationsOnly() {
     }
 
     private boolean isVisibleAdapterForMenu(final ManagedObject objectAdapter) {
-        var spec = objectAdapter.getSpecification();
+        var spec = objectAdapter.objSpec();
         if (spec.isHidden()) {
             // however, this isn't the same as HiddenObjectFacet, so doesn't filter out
             // services that have an imperative hidden() method.
@@ -344,7 +344,7 @@ private static List<BSMenu> buildMenuItemsFromAnnotationsOnly(
 
                 var objectAction = serviceAndAction.getObjectAction();
                 //var service = serviceAndAction.getServiceAdapter();
-                var logicalTypeName = serviceAndAction.getServiceAdapter().getSpecification().logicalTypeName();
+                var logicalTypeName = serviceAndAction.getServiceAdapter().objSpec().logicalTypeName();
                 var actionLayoutData = new ServiceActionLayoutData(logicalTypeName, objectAction.getId());
 
                 var named = objectAction
@@ -380,7 +380,7 @@ private static Set<String> serviceNamesInOrder(
 
         // first, order as defined in causeway.properties
         for (ManagedObject serviceAdapter : serviceAdapters) {
-            var serviceSpec = serviceAdapter.getSpecification();
+            var serviceSpec = serviceAdapter.objSpec();
             // assuming services always provide singular NounForm
             String serviceName = serviceSpec.getSingularName();
             serviceNameOrder.add(serviceName);
@@ -430,7 +430,7 @@ private Stream<ServiceAndAction> streamServiceActions(
             final ManagedObject serviceAdapter,
             final ActionScope actionType) {
 
-        final ObjectSpecification serviceSpec = serviceAdapter.getSpecification();
+        final ObjectSpecification serviceSpec = serviceAdapter.objSpec();
         final Stream<ObjectAction> objectActions = serviceSpec.streamDeclaredActions(actionType, MixedIn.INCLUDED);
 
         return objectActions
@@ -450,7 +450,7 @@ private Stream<ServiceAndAction> streamServiceActions(
     private static Predicate<ManagedObject> with(final DomainServiceLayout.MenuBar menuBar) {
         return (final ManagedObject input) -> {
             final DomainServiceLayoutFacet facet =
-                    input.getSpecification().getFacet(DomainServiceLayoutFacet.class);
+                    input.objSpec().getFacet(DomainServiceLayoutFacet.class);
             return facet != null && facet.getMenuBar() == menuBar;
         };
     }
diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/publish/LifecycleCallbackNotifier.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/publish/LifecycleCallbackNotifier.java
index 1ff11b1c474..22eafe0b798 100644
--- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/publish/LifecycleCallbackNotifier.java
+++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/publish/LifecycleCallbackNotifier.java
@@ -121,7 +121,7 @@ private void dispatch(
             final Class<? extends LifecycleEventFacet> lifecycleEventFacetClass) {
 
         ManagedObjects.asSpecified(entity)
-        .map(ManagedObject::getSpecification)
+        .map(ManagedObject::objSpec)
         .ifPresent(spec->{
             spec.lookupFacet(callbackFacetType)
             .ifPresent(callbackFacet->invokeCallback(callbackFacet, entity));
diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefault.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefault.java
index 0758800b026..02b06523d63 100644
--- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefault.java
@@ -283,7 +283,7 @@ public <T,R> T asyncWrap(
             final AsyncControl<R> asyncControl) {
 
         var targetAdapter = adaptAndGuardAgainstWrappingNotSupported(domainObject);
-        if(targetAdapter.getSpecification().isMixin()) {
+        if(targetAdapter.objSpec().isMixin()) {
             throw _Exceptions.illegalArgument("cannot wrap a mixin instance directly, "
                     + "use WrapperFactory.asyncWrapMixin(...) instead");
         }
@@ -435,7 +435,7 @@ private MemberAndTarget memberAndTargetForRegular(
             final ResolvedMethod method,
             final ManagedObject targetAdapter) {
 
-        var objectMember = targetAdapter.getSpecification().getMember(method).orElse(null);
+        var objectMember = targetAdapter.objSpec().getMember(method).orElse(null);
         if(objectMember == null) {
             return MemberAndTarget.notFound();
         }
@@ -457,7 +457,7 @@ private <T> MemberAndTarget memberAndTargetForMixin(
             final T mixee,
             final ManagedObject mixinAdapter) {
 
-        var mixinMember = mixinAdapter.getSpecification().getMember(method).orElse(null);
+        var mixinMember = mixinAdapter.objSpec().getMember(method).orElse(null);
         if (mixinMember == null) {
             return MemberAndTarget.notFound();
         }
@@ -560,7 +560,7 @@ private ManagedObject adaptAndGuardAgainstWrappingNotSupported(
 
         var adapter = getObjectManager().adapt(domainObject);
         if(ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter)
-                || !adapter.getSpecification().getBeanSort().policy().isWrappingSupported()) {
+                || !adapter.objSpec().getBeanSort().policy().isWrappingSupported()) {
             throw _Exceptions.illegalArgument("Cannot wrap an object of type %s",
                     domainObject.getClass().getName());
         }
diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java
index 519d1b82a55..58ae84364bb 100644
--- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java
+++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java
@@ -111,11 +111,11 @@ public DomainObjectInvocationHandler(
             final SyncControl syncControl,
             final ProxyGenerator proxyGenerator) {
         super(
-                targetAdapter.getSpecification().getMetaModelContext(),
+                targetAdapter.objSpec().getMetaModelContext(),
                 domainObject,
                 syncControl);
 
-        this.mmContext = targetAdapter.getSpecification().getMetaModelContext();
+        this.mmContext = targetAdapter.objSpec().getMetaModelContext();
         this.proxyGenerator = proxyGenerator;
 
         try {
@@ -134,7 +134,7 @@ public DomainObjectInvocationHandler(
                     nsme);
         }
 
-        entityFacet = targetAdapter.getSpecification().entityFacet().orElse(null);
+        entityFacet = targetAdapter.objSpec().entityFacet().orElse(null);
 
         this.mixeeAdapter = mixeeAdapter;
     }
@@ -159,7 +159,7 @@ public Object invoke(final Object proxyObjectUnused, final Method method, final
 
         final ManagedObject targetAdapter = getObjectManager().adapt(getDelegate());
 
-        if(!targetAdapter.getSpecialization().isMixin()) {
+        if(!targetAdapter.specialization().isMixin()) {
             MmAssertionUtils.assertIsBookmarkSupported(targetAdapter);
         }
 
@@ -167,7 +167,7 @@ public Object invoke(final Object proxyObjectUnused, final Method method, final
             return handleTitleMethod(targetAdapter);
         }
 
-        final ObjectSpecification targetSpec = targetAdapter.getSpecification();
+        final ObjectSpecification targetSpec = targetAdapter.objSpec();
         var resolvedMethod = _GenericResolver.resolveMethod(method, targetSpec.getCorrespondingClass())
                 .orElseThrow();
 
@@ -272,7 +272,7 @@ private static ObjectMember determineMixinMember(
         if(domainObjectAdapter == null) {
             return null;
         }
-        var specification = domainObjectAdapter.getSpecification();
+        var specification = domainObjectAdapter.objSpec();
         var objectActions = specification.streamAnyActions(MixedIn.INCLUDED);
         var objectAssociations = specification.streamAssociations(MixedIn.INCLUDED);
 
@@ -303,7 +303,7 @@ private Object handleTitleMethod(final ManagedObject targetAdapter) {
 
         resolveIfRequired(targetAdapter);
 
-        var targetNoSpec = targetAdapter.getSpecification();
+        var targetNoSpec = targetAdapter.objSpec();
         var titleContext = targetNoSpec
                 .createTitleInteractionContext(targetAdapter, InteractionInitiatedBy.FRAMEWORK);
         var titleEvent = titleContext.createInteractionEvent();
@@ -320,7 +320,7 @@ private Object handleSaveMethod(
             notifyListenersAndVetoIfRequired(interactionResult);
         });
 
-        var spec = targetAdapter.getSpecification();
+        var spec = targetAdapter.objSpec();
         if(spec.isEntity()) {
             return runExecutionTask(()->{
                 MmEntityUtils.persistInCurrentTransaction(targetAdapter);
diff --git a/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/menubars/bootstrap/MenuBarsServiceBSTest.java b/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/menubars/bootstrap/MenuBarsServiceBSTest.java
index acc5a41512b..9ed35a5e2f4 100644
--- a/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/menubars/bootstrap/MenuBarsServiceBSTest.java
+++ b/core/runtimeservices/src/test/java/org/apache/causeway/core/runtimeservices/menubars/bootstrap/MenuBarsServiceBSTest.java
@@ -75,7 +75,7 @@ protected void afterSetUp() {
                 .anyMatch(bean->bean.beanClass().equals(Bar.class)));
 
         assertTrue(getMetaModelContext().streamServiceAdapters()
-                .anyMatch(domainObject->domainObject.getSpecification().getCorrespondingClass().equals(Bar.class)));
+                .anyMatch(domainObject->domainObject.objSpec().getCorrespondingClass().equals(Bar.class)));
     }
 
     @Test
diff --git a/persistence/commons/src/main/java/org/apache/causeway/persistence/commons/integration/changetracking/EntityChangeTrackerDefault.java b/persistence/commons/src/main/java/org/apache/causeway/persistence/commons/integration/changetracking/EntityChangeTrackerDefault.java
index 72374a2d25a..f8c22a42e27 100644
--- a/persistence/commons/src/main/java/org/apache/causeway/persistence/commons/integration/changetracking/EntityChangeTrackerDefault.java
+++ b/persistence/commons/src/main/java/org/apache/causeway/persistence/commons/integration/changetracking/EntityChangeTrackerDefault.java
@@ -125,10 +125,10 @@ public class EntityChangeTrackerDefault
 
     @Inject
     public EntityChangeTrackerDefault(
-            EntityPropertyChangePublisher entityPropertyChangePublisher,
-            EntityChangesPublisher entityChangesPublisher,
-            Provider<InteractionProvider> interactionProviderProvider,
-            PreAndPostValueEvaluatorService preAndPostValueEvaluatorService) {
+            final EntityPropertyChangePublisher entityPropertyChangePublisher,
+            final EntityChangesPublisher entityChangesPublisher,
+            final Provider<InteractionProvider> interactionProviderProvider,
+            final PreAndPostValueEvaluatorService preAndPostValueEvaluatorService) {
 
         if(log.isDebugEnabled()) {
             var interactionId = interactionProviderProvider.get().currentInteraction().map(Interaction::getInteractionId).orElseGet(null);
@@ -163,13 +163,13 @@ public int getOrder() {
     /**
      * As used when {@link #enlistCreated(ManagedObject)} or {@link #enlistUpdating(ManagedObject, Function)}
      */
-    private void addPropertyChangeRecordIfAbsent(PropertyChangeRecordId pcrId, PropertyChangeRecord pcr) {
+    private void addPropertyChangeRecordIfAbsent(final PropertyChangeRecordId pcrId, final PropertyChangeRecord pcr) {
         enlistedPropertyChangeRecordsById.computeIfAbsent(pcrId, id -> pcr);
     }
     /**
      * As used when {@link #enlistDeleting(ManagedObject)}.
      */
-    private void addPropertyChangeRecordIfAbsent(PropertyChangeRecordId pcrId, Function<PropertyChangeRecordId, PropertyChangeRecord> func) {
+    private void addPropertyChangeRecordIfAbsent(final PropertyChangeRecordId pcrId, final Function<PropertyChangeRecordId, PropertyChangeRecord> func) {
         enlistedPropertyChangeRecordsById.computeIfAbsent(pcrId, func);
     }
 
@@ -232,7 +232,7 @@ static class Changes {
      * when iterating over the original value set, if any of the properties causes the entity to change state as it is
      * evaluated then a ConcurrentModificationException will be thrown because an enlist will occur.
      */
-    private Set<PropertyChangeRecord> changedRecords(Collection<PropertyChangeRecord> propertyChangeRecords)
+    private Set<PropertyChangeRecord> changedRecords(final Collection<PropertyChangeRecord> propertyChangeRecords)
             throws ConcurrentModificationException {
         return propertyChangeRecords.stream()
                 // set post values, which have been left empty up to now
@@ -309,7 +309,7 @@ private boolean isEntityExcludedForChangePublishing(final ManagedObject entity)
             return true;
         }
 
-        if(!EntityChangePublishingFacet.isPublishingEnabled(entity.getSpecification())) {
+        if(!EntityChangePublishingFacet.isPublishingEnabled(entity.objSpec())) {
             return true; // ignore entities that are not enabled for entity change publishing
         }
 
@@ -325,7 +325,7 @@ private boolean isEntityExcludedForChangePublishing(final ManagedObject entity)
     }
 
     @Override
-    public void beforeCommit(boolean readOnly) {
+    public void beforeCommit(final boolean readOnly) {
         _Xray.publish(this, interactionProviderProvider);
 
         if(log.isDebugEnabled()) {
@@ -341,7 +341,7 @@ public void beforeCommit(boolean readOnly) {
     }
 
     @Override
-    public void afterCompletion(int status) {
+    public void afterCompletion(final int status) {
 
         if(log.isDebugEnabled()) {
             var interactionId = interactionProviderProvider.get().currentInteraction().map(Interaction::getInteractionId).orElse(null);
@@ -351,7 +351,7 @@ public void afterCompletion(int status) {
         clearAndReset();
     }
 
-    private static String decodeStatus(int status) {
+    private static String decodeStatus(final int status) {
         if (status == STATUS_COMMITTED) return "STATUS_COMMITTED";
         if (status == STATUS_ROLLED_BACK) return "STATUS_ROLLED_BACK";
         if (status == STATUS_UNKNOWN) return "STATUS_UNKNOWN";
@@ -372,7 +372,7 @@ public Optional<EntityChanges> getEntityChanges(
             final String userName) {
 
         // a defensive copy of
-        var changeKindByEnlistedAdapter = (Map<Bookmark, EntityChangeKind>) new HashMap<>(this.changeKindByEnlistedAdapter);
+        var changeKindByEnlistedAdapter = new HashMap<>(this.changeKindByEnlistedAdapter);
         if(changeKindByEnlistedAdapter.isEmpty()) {
             return Optional.empty();
         }
diff --git a/persistence/commons/src/main/java/org/apache/causeway/persistence/commons/integration/changetracking/_Xray.java b/persistence/commons/src/main/java/org/apache/causeway/persistence/commons/integration/changetracking/_Xray.java
index 80b4fed10c1..8344ae1c91d 100644
--- a/persistence/commons/src/main/java/org/apache/causeway/persistence/commons/integration/changetracking/_Xray.java
+++ b/persistence/commons/src/main/java/org/apache/causeway/persistence/commons/integration/changetracking/_Xray.java
@@ -105,7 +105,7 @@ private static void addSequence(
                 ManagedObjects.isNullOrUnspecifiedOrEmpty(entity)
                     ? "<empty>"
                     : String.format("%s:\n%s",
-                            entity.getSpecification().logicalTypeName(),
+                            entity.objSpec().logicalTypeName(),
                             "" + entity.getPojo()));
 
         _XrayEvent.event(enteringLabel);
diff --git a/persistence/commons/src/main/java/org/apache/causeway/persistence/commons/integration/version/EntityVersionAccessorDefault.java b/persistence/commons/src/main/java/org/apache/causeway/persistence/commons/integration/version/EntityVersionAccessorDefault.java
index c288475c361..4744d039bc9 100644
--- a/persistence/commons/src/main/java/org/apache/causeway/persistence/commons/integration/version/EntityVersionAccessorDefault.java
+++ b/persistence/commons/src/main/java/org/apache/causeway/persistence/commons/integration/version/EntityVersionAccessorDefault.java
@@ -40,7 +40,7 @@ public class EntityVersionAccessorDefault implements EntityVersionAccessor {
     @Override
     public Object versionOf(final Object domainObject) {
         ManagedObject managedObject = objectManager.adapt(domainObject);
-        EntityFacet facet = managedObject.getSpecification().getFacet(EntityFacet.class);
+        EntityFacet facet = managedObject.objSpec().getFacet(EntityFacet.class);
         if (facet != null) {
             return facet.versionOf(domainObject);
         }
diff --git a/persistence/jdo/datanucleus/src/main/java/org/apache/causeway/persistence/jdo/datanucleus/changetracking/_Utils.java b/persistence/jdo/datanucleus/src/main/java/org/apache/causeway/persistence/jdo/datanucleus/changetracking/_Utils.java
index 76ed5cdba86..524b0204871 100644
--- a/persistence/jdo/datanucleus/src/main/java/org/apache/causeway/persistence/jdo/datanucleus/changetracking/_Utils.java
+++ b/persistence/jdo/datanucleus/src/main/java/org/apache/causeway/persistence/jdo/datanucleus/changetracking/_Utils.java
@@ -58,7 +58,7 @@ ManagedObject adaptEntity(
 
         var objectManager = mmc.getObjectManager();
         var entity = objectManager.adapt(entityPojo);
-        _Assert.assertTrue(entity.getSpecification().isEntity());
+        _Assert.assertTrue(entity.objSpec().isEntity());
         return entity;
     }
 
diff --git a/regressiontests/base/src/main/java/org/apache/causeway/testdomain/util/interaction/DomainObjectTesterFactory.java b/regressiontests/base/src/main/java/org/apache/causeway/testdomain/util/interaction/DomainObjectTesterFactory.java
index 197c6d29765..0015b2b5709 100644
--- a/regressiontests/base/src/main/java/org/apache/causeway/testdomain/util/interaction/DomainObjectTesterFactory.java
+++ b/regressiontests/base/src/main/java/org/apache/causeway/testdomain/util/interaction/DomainObjectTesterFactory.java
@@ -110,7 +110,7 @@ public <T> ActionTester<T> actionTesterForSpecificInteraction(
             final @NonNull ActionInteraction actionInteraction) {
         var managedAction = actionInteraction.getManagedActionElseFail();
         assertEquals(domainObject.getClass(),
-                managedAction.getOwner().getSpecification().getCorrespondingClass());
+                managedAction.getOwner().objSpec().getCorrespondingClass());
         var actionTester = getServiceInjector().injectServicesInto(
                 new ActionTester<>(domainObject, actionInteraction, managedAction));
         actionTester.init();
@@ -667,7 +667,7 @@ public DataTableTester tableTester(
         @SuppressWarnings("unchecked")
         static void updatePojo(final ManagedValue managedValue, @SuppressWarnings("rawtypes") final UnaryOperator replacer) {
             managedValue.update(v->ManagedObject.adaptSingular(
-                    v.getSpecification(),
+                    v.objSpec(),
                     replacer.apply(v.getPojo())));
         }
 
@@ -1191,7 +1191,7 @@ protected Tester(
                 final @NonNull T domainObject) {
             this.domainObjectType = _Casts.uncheckedCast(domainObject.getClass());
             this.vm = MetaModelContext.instanceElseFail().getObjectManager().adapt(domainObject);
-            this.objectSpecification = vm.getSpecification();
+            this.objectSpecification = vm.objSpec();
         }
 
     }
diff --git a/regressiontests/domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java b/regressiontests/domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
index a9dedd0f864..d491f9780fa 100644
--- a/regressiontests/domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
+++ b/regressiontests/domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
@@ -1022,7 +1022,7 @@ void javaRecordAsViewModel(final RecordScenario scenario) {
         final Class<?> classUnderTest = scenario.recordClass;
         final Object sample = scenario.samples.getFirstElseFail();
         var viewModel = MetaModelContext.instanceElseFail().getObjectManager().adapt(sample);
-        var elementType = viewModel.getSpecification();
+        var elementType = viewModel.objSpec();
         var viewmodelFacet = elementType.getFacet(ViewModelFacet.class);
 
         assertEquals(BeanSort.VIEW_MODEL, elementType.getBeanSort());
diff --git a/regressiontests/persistence-jpa/src/test/java/org/apache/causeway/testdomain/persistence/jpa/entitylifecycle/JpaGeneratedLongIdEntityLifecycleTest.java b/regressiontests/persistence-jpa/src/test/java/org/apache/causeway/testdomain/persistence/jpa/entitylifecycle/JpaGeneratedLongIdEntityLifecycleTest.java
index 9d743fc8e02..c8d44217438 100644
--- a/regressiontests/persistence-jpa/src/test/java/org/apache/causeway/testdomain/persistence/jpa/entitylifecycle/JpaGeneratedLongIdEntityLifecycleTest.java
+++ b/regressiontests/persistence-jpa/src/test/java/org/apache/causeway/testdomain/persistence/jpa/entitylifecycle/JpaGeneratedLongIdEntityLifecycleTest.java
@@ -75,7 +75,7 @@ void detached_shouldBeProperlyDetected() {
         var entity = objectManager.adapt(
                 repository.detachedEntity(new JpaEntityGeneratedLongId("test")));
 
-        assertTrue(entity.getSpecification().isEntity());
+        assertTrue(entity.objSpec().isEntity());
         assertEquals(
                 EntityState.TRANSIENT_OR_REMOVED,
                 MmEntityUtils.getEntityState(entity));
diff --git a/regressiontests/persistence-jpa/src/test/java/org/apache/causeway/testdomain/persistence/jpa/entitylifecycle/JpaNonGeneratedStringIdEntityLifecycleTest.java b/regressiontests/persistence-jpa/src/test/java/org/apache/causeway/testdomain/persistence/jpa/entitylifecycle/JpaNonGeneratedStringIdEntityLifecycleTest.java
index cdfc285c1e7..1f55480749b 100644
--- a/regressiontests/persistence-jpa/src/test/java/org/apache/causeway/testdomain/persistence/jpa/entitylifecycle/JpaNonGeneratedStringIdEntityLifecycleTest.java
+++ b/regressiontests/persistence-jpa/src/test/java/org/apache/causeway/testdomain/persistence/jpa/entitylifecycle/JpaNonGeneratedStringIdEntityLifecycleTest.java
@@ -75,7 +75,7 @@ void detached_shouldBeProperlyDetected() {
         var entity = objectManager.adapt(
                 repository.detachedEntity(new JpaEntityNonGeneratedStringId("test")));
 
-        assertTrue(entity.getSpecification().isEntity());
+        assertTrue(entity.objSpec().isEntity());
         assertEquals(
                 EntityState.TRANSIENT_OR_REMOVED,
                 MmEntityUtils.getEntityState(entity));
diff --git a/regressiontests/value/src/test/java/org/apache/causeway/testdomain/value/ActionInteractionProbeImpl.java b/regressiontests/value/src/test/java/org/apache/causeway/testdomain/value/ActionInteractionProbeImpl.java
index f7408bcead7..cc07b4b232a 100644
--- a/regressiontests/value/src/test/java/org/apache/causeway/testdomain/value/ActionInteractionProbeImpl.java
+++ b/regressiontests/value/src/test/java/org/apache/causeway/testdomain/value/ActionInteractionProbeImpl.java
@@ -69,7 +69,7 @@ public void testCommandWithNonEmptyArg(
         var parameterRecorded = valueMarshaller.recoverParameterFrom(paramId, parameterRecordedDto);
         assertNotNull(parameterRecorded);
 
-        assertEquals(valueType, parameterRecorded.getSpecification().getCorrespondingClass(), ()->
+        assertEquals(valueType, parameterRecorded.objSpec().getCorrespondingClass(), ()->
             String.format("command value parsing type mismatch '%s'",
                     _Utils.valueDtoToXml(parameterRecordedDto)));
 
@@ -101,7 +101,7 @@ public void testCommandWithEmptyArg(
         var parameterRecorded = valueMarshaller.recoverParameterFrom(paramId, parameterRecordedDto);
         assertNotNull(parameterRecorded);
 
-        assertEquals(valueType, parameterRecorded.getSpecification().getCorrespondingClass(), ()->
+        assertEquals(valueType, parameterRecorded.objSpec().getCorrespondingClass(), ()->
             String.format("command value parsing type mismatch '%s'",
                     _Utils.valueDtoToXml(parameterRecordedDto)));
 
diff --git a/regressiontests/value/src/test/java/org/apache/causeway/testdomain/value/PropertyInteractionProbeImpl.java b/regressiontests/value/src/test/java/org/apache/causeway/testdomain/value/PropertyInteractionProbeImpl.java
index 5fd436de36a..f8d55cde842 100644
--- a/regressiontests/value/src/test/java/org/apache/causeway/testdomain/value/PropertyInteractionProbeImpl.java
+++ b/regressiontests/value/src/test/java/org/apache/causeway/testdomain/value/PropertyInteractionProbeImpl.java
@@ -236,7 +236,7 @@ public void testCommand(
         var newValueRecorded = valueMarshaller.recoverPropertyFrom(propertyDto);
         assertNotNull(newValueRecorded);
 
-        assertEquals(valueType, newValueRecorded.getSpecification().getCorrespondingClass(), ()->
+        assertEquals(valueType, newValueRecorded.objSpec().getCorrespondingClass(), ()->
             String.format("command value parsing type mismatch '%s'",
                     _Utils.valueDtoToXml(newValueRecordedDto)));
 
diff --git a/regressiontests/viewers-common/src/test/java/org/apache/causeway/testdomain/viewers/common/wkt/InteractionTestWkt.java b/regressiontests/viewers-common/src/test/java/org/apache/causeway/testdomain/viewers/common/wkt/InteractionTestWkt.java
index 8dcc3e362ef..74323ed9493 100644
--- a/regressiontests/viewers-common/src/test/java/org/apache/causeway/testdomain/viewers/common/wkt/InteractionTestWkt.java
+++ b/regressiontests/viewers-common/src/test/java/org/apache/causeway/testdomain/viewers/common/wkt/InteractionTestWkt.java
@@ -120,7 +120,7 @@ void shouldHaveARequestCycle() {
     @Test
     void propertyModels_shouldBeInSyncWithInteractionAPI() {
 
-        var objectSpec = domainObject.getSpecification();
+        var objectSpec = domainObject.objSpec();
         var objectModel = UiObjectWkt.ofAdapter(domainObject);
 
         assertEquals(domainObject.getBookmark().get(), objectModel.getOwnerBookmark());
diff --git a/viewers/commons/model/src/main/java/org/apache/causeway/viewer/commons/model/action/UiActionForm.java b/viewers/commons/model/src/main/java/org/apache/causeway/viewer/commons/model/action/UiActionForm.java
index 6605e4a3eb1..2ec15693118 100644
--- a/viewers/commons/model/src/main/java/org/apache/causeway/viewer/commons/model/action/UiActionForm.java
+++ b/viewers/commons/model/src/main/java/org/apache/causeway/viewer/commons/model/action/UiActionForm.java
@@ -60,7 +60,7 @@ default Consent getVisibilityConsent() {
         }
 
         // check whether action owner type is hidden
-        if (getActionOwner().getSpecification().isHidden()) {
+        if (getActionOwner().objSpec().isHidden()) {
             return Veto.DEFAULT;
         }
 
diff --git a/viewers/commons/model/src/main/java/org/apache/causeway/viewer/commons/model/layout/UiGridLayout.java b/viewers/commons/model/src/main/java/org/apache/causeway/viewer/commons/model/layout/UiGridLayout.java
index 77d064fece2..7591aa2ce25 100644
--- a/viewers/commons/model/src/main/java/org/apache/causeway/viewer/commons/model/layout/UiGridLayout.java
+++ b/viewers/commons/model/src/main/java/org/apache/causeway/viewer/commons/model/layout/UiGridLayout.java
@@ -80,7 +80,7 @@ public <C, T> void visit(final Visitor<C, T> visitor) {
     }
 
     private Optional<BSGrid> initGridData() {
-        return Facets.bootstrapGrid(managedObject.getSpecification(), managedObject)
+        return Facets.bootstrapGrid(managedObject.objSpec(), managedObject)
         .map(this::attachAssociatedActions);
     }
 
@@ -90,7 +90,7 @@ private BSGrid attachAssociatedActions(final BSGrid bSGrid) {
         var primedActions = bSGrid.getAllActionsById();
         final Set<String> actionIdsAlreadyAdded = _Sets.newHashSet(primedActions.keySet());
 
-        managedObject.getSpecification().streamProperties(MixedIn.INCLUDED)
+        managedObject.objSpec().streamProperties(MixedIn.INCLUDED)
         .forEach(property->{
             Optional.ofNullable(
                     bSGrid.getAllPropertiesById().get(property.getId()))
diff --git a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/meta/CommonMetaFetcher.java b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/meta/CommonMetaFetcher.java
index 22ae3c9eafa..8db5277145a 100644
--- a/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/meta/CommonMetaFetcher.java
+++ b/viewers/graphql/model/src/main/java/org/apache/causeway/viewer/graphql/model/domain/common/query/meta/CommonMetaFetcher.java
@@ -66,7 +66,7 @@ public String version() {
         return managedObject()
                 .map(managedObject -> {
                     var domainPojo = managedObject.getPojo();
-                    var entityFacet = managedObject.getSpecification().getFacet(EntityFacet.class);
+                    var entityFacet = managedObject.objSpec().getFacet(EntityFacet.class);
                     if (entityFacet != null) {
                         var object = entityFacet.versionOf(domainPojo);
                         return object != null ? object.toString() : null;
@@ -89,7 +89,7 @@ public String title() {
     public String cssClass() {
         return managedObject()
                 .map(managedObject -> {
-                    var facet = managedObject.getSpecification().getFacet(CssClassFacet.class);
+                    var facet = managedObject.objSpec().getFacet(CssClassFacet.class);
                     return facet != null ? facet.cssClass(managedObject) : null;
                 })
                 .orElse(null);
@@ -98,7 +98,7 @@ public String cssClass() {
     public String layout() {
         return managedObject()
                 .map(managedObject -> {
-                    var facet = managedObject.getSpecification().getFacet(LayoutPrefixFacet.class);
+                    var facet = managedObject.objSpec().getFacet(LayoutPrefixFacet.class);
                     return facet != null ? facet.layoutPrefix(managedObject) : null;
                 })
                 .orElse(null);
@@ -112,7 +112,7 @@ public String icon() {
         return resource("icon");
     }
 
-    private String resource(String resource) {
+    private String resource(final String resource) {
         return managedObject()
                 .flatMap(Bookmarkable::getBookmark
                 ).map(bookmark -> String.format(
diff --git a/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/controller/ResourceController.java b/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/controller/ResourceController.java
index 50257b1644c..19e382e6000 100644
--- a/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/controller/ResourceController.java
+++ b/viewers/graphql/viewer/src/main/java/org/apache/causeway/viewer/graphql/viewer/controller/ResourceController.java
@@ -192,13 +192,13 @@ public ResponseEntity<byte[]> icon(
 
     @Nullable
     private static Grid gridOf(final ManagedObject managedObject) {
-        var facet = managedObject.getSpecification().getFacet(GridFacet.class);
+        var facet = managedObject.objSpec().getFacet(GridFacet.class);
         return facet != null ? facet.getGrid(managedObject) : null;
     }
 
     private Optional<Object> valueOfProperty(final String logicalTypeName, final String id, final String propertyId) {
         return lookup(logicalTypeName, id)
-                .map(managedObject -> new ManagedObjectAndPropertyIfAny(managedObject, managedObject.getSpecification().getProperty(propertyId)))
+                .map(managedObject -> new ManagedObjectAndPropertyIfAny(managedObject, managedObject.objSpec().getProperty(propertyId)))
                 .filter(ManagedObjectAndPropertyIfAny::isPropertyPresent)
                 .map(ManagedObjectAndProperty::of)
                 .map(ManagedObjectAndProperty::value)
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
index ff3b8ca2ab3..939493b2f2e 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
@@ -150,7 +150,7 @@ public DomainObjectReprRenderer with(final ManagedObject objectAdapter) {
                 .newLinkToBuilder(
                         getResourceContext(),
                         Rel.DOMAIN_TYPE,
-                        objectAdapter.getSpecification())
+                        objectAdapter.objSpec())
                 .build()
                 .getString("href");
         addMediaTypeParams(X_RO_DOMAIN_TYPE, domainTypeHref);
@@ -164,7 +164,7 @@ public JsonRepresentation render() {
             return null;
         }
 
-        final boolean isService = objectAdapter.getSpecification().isInjectable();
+        final boolean isService = objectAdapter.objSpec().isInjectable();
 
         if (!(mode.isArgs())) {
 
@@ -187,7 +187,7 @@ public JsonRepresentation render() {
 
             // serviceId or instance Id
             if (isService) {
-                representation.mapPutString("serviceId", objectAdapter.getSpecification().logicalTypeName());
+                representation.mapPutString("serviceId", objectAdapter.objSpec().logicalTypeName());
             } else {
                 oidIfAny.ifPresent(oid->{
                     Optional.ofNullable(oid.logicalTypeName())
@@ -223,7 +223,7 @@ public JsonRepresentation render() {
             getExtensions().mapPutBoolean("isPersistent", ManagedObjects.isIdentifiable(objectAdapter));
             if(isService) {
 
-                Facets.domainServiceLayoutMenuBar(objectAdapter.getSpecification())
+                Facets.domainServiceLayoutMenuBar(objectAdapter.objSpec())
                 .ifPresent(menuBar->
                         getExtensions().mapPut("menuBar", menuBar));
 
@@ -248,12 +248,12 @@ private void addLinkToSelf() {
     }
 
     private void addLinkToDescribedBy() {
-        final JsonRepresentation link = DomainTypeReprRenderer.newLinkToBuilder(getResourceContext(), Rel.DESCRIBEDBY, objectAdapter.getSpecification()).build();
+        final JsonRepresentation link = DomainTypeReprRenderer.newLinkToBuilder(getResourceContext(), Rel.DESCRIBEDBY, objectAdapter.objSpec()).build();
 
         final LinkFollowSpecs linkFollower = getLinkFollowSpecs().follow("links");
         if (linkFollower.matches(link)) {
             final DomainTypeReprRenderer renderer = new DomainTypeReprRenderer(getResourceContext(), linkFollower, JsonRepresentation.newMap());
-            renderer.with(objectAdapter.getSpecification());
+            renderer.with(objectAdapter.objSpec());
             link.mapPutJsonRepresentation("value", renderer.render());
         }
         getLinks().arrayAdd(link);
@@ -281,7 +281,7 @@ private void addLinkToUp() {
     private DomainObjectReprRenderer withMembers(final ManagedObject objectAdapter) {
         final JsonRepresentation appendTo =
                 mode.isUpdatePropertiesLinkArgs() ? representation : JsonRepresentation.newMap();
-        final List<ObjectAssociation> associations = objectAdapter.getSpecification()
+        final List<ObjectAssociation> associations = objectAdapter.objSpec()
                 .streamAssociations(MixedIn.INCLUDED)
                 .collect(Collectors.toList());
 
@@ -293,7 +293,7 @@ private DomainObjectReprRenderer withMembers(final ManagedObject objectAdapter)
             }
 
             if (mode.isRegular()) {
-                final Stream<ObjectAction> actions = objectAdapter.getSpecification()
+                final Stream<ObjectAction> actions = objectAdapter.objSpec()
                         .streamAnyActions(MixedIn.INCLUDED);
 
                 addActions(objectAdapter, actions, appendTo);
@@ -405,7 +405,7 @@ private void addPersistLinkIfTransientAndPersistable() {
                 new DomainObjectReprRenderer(getResourceContext(), null, JsonRepresentation.newMap());
         final JsonRepresentation domainObjectRepr = renderer.with(objectAdapter).asPersistLinkArguments().render();
 
-        final String domainType = objectAdapter.getSpecification().logicalTypeName();
+        final String domainType = objectAdapter.objSpec().logicalTypeName();
         final LinkBuilder persistLinkBuilder = LinkBuilder.newBuilder(getResourceContext(), Rel.PERSIST.getName(), RepresentationType.DOMAIN_OBJECT, "objects/%s", domainType).withHttpMethod(RestfulHttpMethod.POST).withArguments(domainObjectRepr);
         getLinks().arrayAdd(persistLinkBuilder.build());
     }
@@ -433,7 +433,7 @@ private void addUpdatePropertiesLinkIfRequired() {
         if (!ManagedObjects.isIdentifiable(objectAdapter)) {
             return;
         }
-        final boolean isService = objectAdapter.getSpecification().isInjectable();
+        final boolean isService = objectAdapter.objSpec().isInjectable();
         if(isService) {
             return;
         }
@@ -455,7 +455,7 @@ public static Object valueOrRef(
             final JsonValueEncoderService jsonValueEncoder,
             final ManagedObject domainObject) {
 
-        var spec = domainObject.getSpecification();
+        var spec = domainObject.objSpec();
         if(spec.isValue()) {
             var context2 = JsonValueConverter.Context.of(objectFeature, context.config().isSuppressMemberExtensions());
             return jsonValueEncoder.asObject(domainObject, context2);
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/DomainServiceLinkTo.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/DomainServiceLinkTo.java
index 69d3cebfaf3..6152a2bb3ec 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/DomainServiceLinkTo.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/DomainServiceLinkTo.java
@@ -28,7 +28,7 @@ public class DomainServiceLinkTo extends DomainObjectLinkTo {
 
     @Override
     public ObjectAdapterLinkTo with(final ManagedObject objectAdapter) {
-        serviceId = objectAdapter.getSpecification().logicalTypeName();
+        serviceId = objectAdapter.objSpec().logicalTypeName();
         return super.with(objectAdapter);
     }
 
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ListReprRenderer.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ListReprRenderer.java
index 4336d6bebbe..d8c797ccced 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ListReprRenderer.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ListReprRenderer.java
@@ -57,7 +57,7 @@ public ListReprRenderer usingLinkToBuilder(final ObjectAdapterLinkTo objectAdapt
     public ListReprRenderer with(final Stream<ManagedObject> objectAdapters) {
         this.objectAdapters = objectAdapters!=null
                 ? objectAdapters
-                        .filter(adapter->!adapter.getSpecification().isHidden())
+                        .filter(adapter->!adapter.objSpec().isHidden())
                         .collect(Collectors.toList())
                         : null;
                         return this;
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
index 79c6ad36d67..bc2788a8d97 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
@@ -145,8 +145,8 @@ private Object paramDetails(final ManagedParameter paramMod, final ParameterNego
         final JsonRepresentation paramRep = JsonRepresentation.newMap();
         paramRep.mapPutInt("num", paramMeta.getParameterIndex());
         paramRep.mapPutString("id", paramMeta.getId());
-        paramRep.mapPutString("name", paramMeta.getFriendlyName(objectAdapter.asSupplier()));
-        paramRep.mapPut("description", paramMeta.getDescription(objectAdapter.asSupplier()));
+        paramRep.mapPutString("name", paramMeta.getFriendlyName(objectAdapter));
+        paramRep.mapPut("description", paramMeta.getDescription(objectAdapter));
         final Object paramChoices = choicesFor(paramMod, paramNeg);
         if (paramChoices != null) {
             paramRep.mapPut("choices", paramChoices);
@@ -195,7 +195,7 @@ protected void addLinksToFormalDomainModel() {
         if(resourceContext.config().isSuppressDescribedByLinks()) {
             return;
         }
-        final JsonRepresentation link = ActionDescriptionReprRenderer.newLinkToBuilder(resourceContext, Rel.DESCRIBEDBY, objectAdapter.getSpecification(), objectMember).build();
+        final JsonRepresentation link = ActionDescriptionReprRenderer.newLinkToBuilder(resourceContext, Rel.DESCRIBEDBY, objectAdapter.objSpec(), objectMember).build();
         getLinks().arrayAdd(link);
     }
 
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectAndActionInvocation.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectAndActionInvocation.java
index 1c20f2c5bbf..c8d0dac12a2 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectAndActionInvocation.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectAndActionInvocation.java
@@ -76,7 +76,7 @@ public ActionResultRepresentation.ResultType determineResultType() {
         //FIXME following decision tree should not depend on the returned runtime types
         // but on the returnTypeSpec,
         // which is introspected eagerly on application start and should be the binding contract
-        var actualReturnTypeSpec = returnedAdapter.getSpecification();
+        var actualReturnTypeSpec = returnedAdapter.objSpec();
 
         if (ManagedObjects.isPacked(returnedAdapter)
                 || isVector(actualReturnTypeSpec)) {
@@ -93,7 +93,7 @@ public ActionResultRepresentation.ResultType determineResultType() {
 
             // inspect the collection's elements
             var isListOfDomainObjects = streamElementAdapters()
-                    .allMatch(elementAdapter->!isScalarValue(elementAdapter.getSpecification()));
+                    .allMatch(elementAdapter->!isScalarValue(elementAdapter.objSpec()));
 
             return isListOfDomainObjects
                     ? ActionResultRepresentation.ResultType.LIST
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectCollectionReprRenderer.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectCollectionReprRenderer.java
index f88e297f909..a36f8cb0de1 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectCollectionReprRenderer.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectCollectionReprRenderer.java
@@ -161,7 +161,7 @@ protected void addLinksToFormalDomainModel() {
         }
         final JsonRepresentation link =
                 CollectionDescriptionReprRenderer
-                .newLinkToBuilder(resourceContext, Rel.DESCRIBEDBY, objectAdapter.getSpecification(), objectMember).build();
+                .newLinkToBuilder(resourceContext, Rel.DESCRIBEDBY, objectAdapter.objSpec(), objectMember).build();
         getLinks().arrayAdd(link);
     }
 
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectPropertyReprRenderer.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectPropertyReprRenderer.java
index c2b5cd1499e..e35c790f86d 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectPropertyReprRenderer.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ObjectPropertyReprRenderer.java
@@ -85,7 +85,7 @@ private void addValue(final LinkFollowSpecs linkFollower) {
                 ? valueAdapterIfAny
                 : ManagedObject.empty(objectMember.getElementType());
 
-        var spec = valueAdapter.getSpecification();
+        var spec = valueAdapter.objSpec();
 
         if (spec.isValue()) {
             jsonValueEncoder
@@ -198,7 +198,7 @@ protected void addLinksToFormalDomainModel() {
         if(resourceContext.config().isSuppressDescribedByLinks()) {
             return;
         }
-        final JsonRepresentation link = PropertyDescriptionReprRenderer.newLinkToBuilder(getResourceContext(), Rel.DESCRIBEDBY, objectAdapter.getSpecification(), objectMember).build();
+        final JsonRepresentation link = PropertyDescriptionReprRenderer.newLinkToBuilder(getResourceContext(), Rel.DESCRIBEDBY, objectAdapter.objSpec(), objectMember).build();
         getLinks().arrayAdd(link);
     }
 
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ScalarValueReprRenderer.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ScalarValueReprRenderer.java
index d27fc072937..0fe99019738 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ScalarValueReprRenderer.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/ScalarValueReprRenderer.java
@@ -64,7 +64,7 @@ public MediaType getMediaType() {
 
     @Override
     public ScalarValueReprRenderer with(final ManagedObject objectAdapter) {
-        if (!objectAdapter.getSpecification().isValue()) {
+        if (!objectAdapter.objSpec().isValue()) {
             throw ReprRendererException.create("Not an (encodable) value", objectAdapter.getTitle());
         }
 
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/service/conneg/ContentNegotiationServiceOrgApacheCausewayV2.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/service/conneg/ContentNegotiationServiceOrgApacheCausewayV2.java
index 7a9a36370af..99ac5912d7c 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/service/conneg/ContentNegotiationServiceOrgApacheCausewayV2.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/service/conneg/ContentNegotiationServiceOrgApacheCausewayV2.java
@@ -265,7 +265,7 @@ public Response.ResponseBuilder buildResponse(
             objectAndActionInvocation.streamElementAdapters()
             .map(elementAdapter->{
                 var dto = dtoForValue(returnedAdapter)
-                        .orElseGet(()->elementAdapter.getSpecification().getCorrespondingClass());
+                        .orElseGet(()->elementAdapter.objSpec().getCorrespondingClass());
                 return dto;
             })
             .forEach(rootRepresentation::arrayAdd);
@@ -305,10 +305,10 @@ public Response.ResponseBuilder buildResponse(
 
     private Optional<Object> dtoForValue(final @Nullable ManagedObject valueObject) {
         if(ManagedObjects.isNullOrUnspecifiedOrEmpty(valueObject)
-                || !valueObject.getSpecification().isValue()) {
+                || !valueObject.objSpec().isValue()) {
             return Optional.empty();
         }
-        var valSpec = valueObject.getSpecification();
+        var valSpec = valueObject.objSpec();
         var dto = valSpec.isCompositeValue()
                 ? ScalarValueDtoV2.forValue(valueObject.getPojo(),
                         //XXX honor value semantics context?
@@ -345,7 +345,7 @@ private void appendObjectTo(
 
         var where = resourceContext.getWhere();
 
-        owner.getSpecification()
+        owner.objSpec()
         .streamCollections(MixedIn.INCLUDED)
         .forEach(collection->{
 
@@ -373,7 +373,7 @@ private void appendPropertiesTo(
 
         var interactionInitiatedBy = resourceContext.getInteractionInitiatedBy();
         var where = resourceContext.getWhere();
-        final Stream<OneToOneAssociation> properties = objectAdapter.getSpecification()
+        final Stream<OneToOneAssociation> properties = objectAdapter.objSpec()
                 .streamProperties(MixedIn.INCLUDED);
 
         properties.forEach(property->{
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/service/valuerender/JsonValueConverter.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/service/valuerender/JsonValueConverter.java
index 12d01621b12..66c70c738bf 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/service/valuerender/JsonValueConverter.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/service/valuerender/JsonValueConverter.java
@@ -111,7 +111,7 @@ public OptionalInt maxFractionalDigits(final @Nullable ManagedObject value) {
             private Can<FacetHolder> facetHolders(final @Nullable ManagedObject value) {
                 return ManagedObjects.isNullOrUnspecifiedOrEmpty(value)
                     ? Can.of(objectFeature)
-                    : Can.of(objectFeature, value.getSpecification());
+                    : Can.of(objectFeature, value.objSpec());
             }
         }
 
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/service/valuerender/JsonValueEncoderServiceDefault.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/service/valuerender/JsonValueEncoderServiceDefault.java
index c45a504e0f7..aacf8deb611 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/service/valuerender/JsonValueEncoderServiceDefault.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/causeway/viewer/restfulobjects/rendering/service/valuerender/JsonValueEncoderServiceDefault.java
@@ -26,14 +26,15 @@
 import jakarta.inject.Inject;
 import jakarta.inject.Named;
 
-import org.springframework.beans.factory.annotation.Qualifier;
+import org.jspecify.annotations.NonNull;
 import org.jspecify.annotations.Nullable;
+
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Service;
 import org.springframework.util.ClassUtils;
 
 import org.apache.causeway.applib.annotation.PriorityPrecedence;
 import org.apache.causeway.applib.value.semantics.ValueDecomposition;
-import org.apache.causeway.applib.value.semantics.ValueSemanticsProvider;
 import org.apache.causeway.commons.functional.Try;
 import org.apache.causeway.commons.internal.assertions._Assert;
 import org.apache.causeway.commons.internal.base._Casts;
@@ -51,8 +52,6 @@
 import org.apache.causeway.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.causeway.viewer.restfulobjects.rendering.service.valuerender.JsonValueConverter.Context;
 
-import org.jspecify.annotations.NonNull;
-
 import lombok.extern.log4j.Log4j2;
 
 @Service
@@ -97,7 +96,7 @@ public ManagedObject asAdapter(
         if(spec.isCompositeValue()) {
             _Assert.assertTrue(valueRepr.isString(), ()->"expected to receive a String originating from ValueDecomposition#stringify");
             var valueFacet = spec.valueFacetElseFail();
-            var valSemantics = (ValueSemanticsProvider<?>)valueFacet.selectDefaultSemantics().orElseThrow();
+            var valSemantics = valueFacet.selectDefaultSemantics().orElseThrow();
             var valDecomposition = ValueDecomposition.destringify(ValueType.COMPOSITE, valueRepr.asString());
             var pojo = valSemantics.compose(valDecomposition);
             return ManagedObject.value(spec, pojo);
@@ -167,7 +166,7 @@ public void appendValueAndFormat(
             final JsonRepresentation repr,
             final Context context) {
 
-        var valueSpec = valueAdapter.getSpecification();
+        var valueSpec = valueAdapter.objSpec();
         var valueClass = valueSpec.getCorrespondingClass();
         var jsonValueConverter = converterByClass.get(valueClass);
         if(jsonValueConverter != null) {
@@ -222,11 +221,11 @@ private static Optional<ValueDecomposition> decompose(final ManagedObject valueA
         if(ManagedObjects.isNullOrUnspecifiedOrEmpty(valueAdapter)) {
             return Optional.empty();
         }
-        var valueClass = valueAdapter.getSpecification().getCorrespondingClass();
-        var decompositionIfAny = Facets.valueDefaultSemantics(valueAdapter.getSpecification(), valueClass)
+        var valueClass = valueAdapter.objSpec().getCorrespondingClass();
+        var decompositionIfAny = Facets.valueDefaultSemantics(valueAdapter.objSpec(), valueClass)
                 .map(composer->composer.decompose(_Casts.uncheckedCast(valueAdapter.getPojo())));
         if(decompositionIfAny.isEmpty()) {
-            var valueSpec = valueAdapter.getSpecification();
+            var valueSpec = valueAdapter.objSpec();
             log.warn("{Could not resolve a ValueComposer for {}, "
                     + "falling back to rendering as 'null'. "
                     + "Make sure the framework has access to a ValueSemanticsProvider<{}> "
@@ -242,7 +241,7 @@ private static Optional<ValueDecomposition> decompose(final ManagedObject valueA
     @Nullable
     public Object asObject(final @NonNull ManagedObject adapter, final JsonValueConverter.Context context) {
 
-        var objectSpec = adapter.getSpecification();
+        var objectSpec = adapter.objSpec();
         var cls = objectSpec.getCorrespondingClass();
 
         var jsonValueConverter = converterByClass.get(cls);
diff --git a/viewers/restfulobjects/rendering/src/test/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest.java b/viewers/restfulobjects/rendering/src/test/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest.java
index 44245a3570e..a7b86f0f9ee 100644
--- a/viewers/restfulobjects/rendering/src/test/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest.java
+++ b/viewers/restfulobjects/rendering/src/test/java/org/apache/causeway/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest.java
@@ -137,7 +137,7 @@ void whenReprIsBoolean(final Class<?> correspondingClass) {
         var adapter = jsonValueEncoder.asAdapter(spec, representation, null);
 
         // then
-        assertSame(spec, adapter.getSpecification());
+        assertSame(spec, adapter.objSpec());
     }
 
     @ParameterizedTest
@@ -152,7 +152,7 @@ void whenReprIsInteger(final Class<?> correspondingClass) {
         var adapter = jsonValueEncoder.asAdapter(spec, representation, null);
 
         // then
-        assertSame(spec, adapter.getSpecification());
+        assertSame(spec, adapter.objSpec());
     }
 
     @ParameterizedTest
@@ -167,7 +167,7 @@ void whenReprIsLong(final Class<?> correspondingClass) {
         var adapter = jsonValueEncoder.asAdapter(spec, representation, null);
 
         // then
-        assertSame(spec, adapter.getSpecification());
+        assertSame(spec, adapter.objSpec());
     }
 
     @ParameterizedTest
@@ -182,7 +182,7 @@ void whenReprIsDouble(final Class<?> correspondingClass) {
         var adapter = jsonValueEncoder.asAdapter(spec, representation, null);
 
         // then
-        assertSame(spec, adapter.getSpecification());
+        assertSame(spec, adapter.objSpec());
     }
 
     @Test
@@ -196,7 +196,7 @@ void whenReprIsBigInteger() throws Exception {
         var adapter = jsonValueEncoder.asAdapter(spec, representation, null);
 
         // then
-        assertSame(spec, adapter.getSpecification());
+        assertSame(spec, adapter.objSpec());
     }
 
     @Test
@@ -210,7 +210,7 @@ void whenReprIsBigDecimal() throws Exception {
         var adapter = jsonValueEncoder.asAdapter(spec, representation, null);
 
         // then
-        assertSame(spec, adapter.getSpecification());
+        assertSame(spec, adapter.objSpec());
     }
 
     @Test
@@ -223,7 +223,7 @@ void whenReprIsString() throws Exception {
         var adapter = jsonValueEncoder.asAdapter(spec, representation, null);
 
         // then
-        assertSame(spec, adapter.getSpecification());
+        assertSame(spec, adapter.objSpec());
     }
 
 }
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
index b34d26fc702..855877d4b4b 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
@@ -134,7 +134,7 @@ public Response persist(
                     .createWithBody(HttpStatusCode.BAD_REQUEST, objectRepr, "Illegal property value"));
         }
 
-        final Consent validity = adapter.getSpecification().isValid(adapter, InteractionInitiatedBy.USER);
+        final Consent validity = adapter.objSpec().isValid(adapter, InteractionInitiatedBy.USER);
         if (validity.isVetoed()) {
             throw _EndpointLogging.error(log, "POST /objects/{}", domainType,
                     RestfulObjectsApplicationException
@@ -211,7 +211,7 @@ public Response object(
                             HttpStatusCode.BAD_REQUEST, argRepr, "Illegal property value"));
         }
 
-        final Consent validity = objectAdapter.getSpecification().isValid(objectAdapter, InteractionInitiatedBy.USER);
+        final Consent validity = objectAdapter.objSpec().isValid(objectAdapter, InteractionInitiatedBy.USER);
         if (validity.isVetoed()) {
             throw _EndpointLogging.error(log, "PUT /objects/{}/{}", domainType, instanceId,
                     RestfulObjectsApplicationException
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/ObjectAdapterUpdateHelper.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/ObjectAdapterUpdateHelper.java
index ba8b2a7ceb6..dca3800a65d 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/ObjectAdapterUpdateHelper.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/causeway/viewer/restfulobjects/viewer/resources/ObjectAdapterUpdateHelper.java
@@ -64,7 +64,7 @@ boolean copyOverProperties(
 
         var allOk = _Refs.booleanRef(true); // simply a non-thread-safe boolean reference
 
-        objectAdapter.getSpecification().streamAssociations(MixedIn.EXCLUDED)
+        objectAdapter.objSpec().streamAssociations(MixedIn.EXCLUDED)
         .filter(ObjectAssociation.Predicates.PROPERTIES) // properties only
         .forEach(association->{
 
@@ -116,9 +116,9 @@ private boolean copyOverProperty(
             // otherwise, is an error.
             final String invalidReason = propertiesMap.getString("x-ro-invalidReason");
             if(invalidReason != null) {
-                propertiesMap.mapPutString("x-ro-invalidReason", invalidReason + "; " + property.getFriendlyName(objectAdapter.asSupplier()));
+                propertiesMap.mapPutString("x-ro-invalidReason", invalidReason + "; " + property.getFriendlyName(objectAdapter));
             } else {
-                propertiesMap.mapPutString("x-ro-invalidReason", "Mandatory field(s) missing: " + property.getFriendlyName(objectAdapter.asSupplier()));
+                propertiesMap.mapPutString("x-ro-invalidReason", "Mandatory field(s) missing: " + property.getFriendlyName(objectAdapter));
             }
             allOk = false;
             return allOk;
diff --git a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ActionResultModel.java b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ActionResultModel.java
index a5183cb9f14..62f127f6ae7 100644
--- a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ActionResultModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ActionResultModel.java
@@ -58,7 +58,7 @@ public static ActionResultModel determineFor(
             return new ActionResultModel(ActionResultResponseType.VOID_AS_EMPTY, resultAdapter);
         }
 
-        var resultSpec = resultAdapter.getSpecification();
+        var resultSpec = resultAdapter.objSpec();
         if (!(resultAdapter instanceof PackedManagedObject)) {
 
             // scalar ...
diff --git a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ParameterModel.java b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ParameterModel.java
index 6e814bb0e76..761283b8428 100644
--- a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ParameterModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ParameterModel.java
@@ -66,7 +66,7 @@ private ParameterModel(
     public String validate(final @NonNull ManagedObject proposedArg) {
         //TODO[CAUSEWAY-3764] workaround for org.apache.wicket.markup.html.form.upload.FileUpload leaking into the meta-model
         //  find the root cause then clean-up
-        if(proposedArg.getSpecification().getBeanSort().isUnknown()) {
+        if(proposedArg.objSpec().getBeanSort().isUnknown()) {
             return null;
         }
         proposedValue().getValue().setValue(proposedArg); // updates the pending parameter value
diff --git a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/UiObjectWkt.java b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/UiObjectWkt.java
index 065d3360c3d..535413a1d20 100644
--- a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/UiObjectWkt.java
+++ b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/UiObjectWkt.java
@@ -261,7 +261,7 @@ public UiAttributeWkt getPropertyModel(
     public Stream<Bookmark> streamPropertyBookmarks() {
         var candidateAdapter = this.getObject();
 
-        return candidateAdapter.getSpecification()
+        return candidateAdapter.objSpec()
         .streamProperties(MixedIn.EXCLUDED)
         .map(prop->
             ManagedObjects.bookmark(prop.get(candidateAdapter, InteractionInitiatedBy.PASS_THROUGH))
diff --git a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ValueModel.java b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ValueModel.java
index 590735e6a21..5bfd8b99f6d 100644
--- a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ValueModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/ValueModel.java
@@ -75,7 +75,7 @@ public ManagedObject getObject() {
     }
 
     public ObjectSpecification elementType() {
-        return getObject().getSpecification();
+        return getObject().objSpec();
     }
 
 }
diff --git a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/HasBookmarkedOwnerAbstract.java b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/HasBookmarkedOwnerAbstract.java
index dd769f442e7..9c9f08eda50 100644
--- a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/HasBookmarkedOwnerAbstract.java
+++ b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/HasBookmarkedOwnerAbstract.java
@@ -44,7 +44,7 @@ public final BookmarkedObjectWkt bookmarkedObjectModel() {
 
     public final ObjectSpecification getTypeOfSpecification() {
         // serving this from a potentially unattached entity seems safe
-        return bookmarkedObjectModel().getObject().getSpecification();
+        return bookmarkedObjectModel().getObject().objSpec();
     }
 
     /** governs how to populate the BookmarkPanel in the UI */
diff --git a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/act/ActionInteractionWkt.java b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/act/ActionInteractionWkt.java
index be9930f3863..2cf1497ae99 100644
--- a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/act/ActionInteractionWkt.java
+++ b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/act/ActionInteractionWkt.java
@@ -97,7 +97,7 @@ public static ActionInteractionWkt forEntity(
             final ParameterModel associatedWithParameterIfAny,
             final CollectionModel associatedWithCollectionIfAny) {
 
-        var onwerSpec = parentEntityModel.getBookmarkedOwner().getSpecification();
+        var onwerSpec = parentEntityModel.getBookmarkedOwner().objSpec();
         var objectAction = onwerSpec.getAction(actionIdentifier.memberLogicalName());
 
         return new ActionInteractionWkt(
diff --git a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/prop/PropertyInteractionWkt.java b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/prop/PropertyInteractionWkt.java
index 122cea847dc..025ce157291 100644
--- a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/prop/PropertyInteractionWkt.java
+++ b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/interaction/prop/PropertyInteractionWkt.java
@@ -122,7 +122,7 @@ private PropertyInteraction loadPropertyInteraction() {
             ManagedProperty.lookupProperty(getBookmarkedOwner(), memberId, where)
             .orElseThrow(()->_Exceptions.noSuchElement("property '%s' in %s",
                     memberId,
-                    getBookmarkedOwner().getSpecification())));
+                    getBookmarkedOwner().objSpec())));
     }
 
     /**
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/attributes/markup/MarkupAttributePanelFactories.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/attributes/markup/MarkupAttributePanelFactories.java
index 950f61026bc..9c061d55217 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/attributes/markup/MarkupAttributePanelFactories.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/attributes/markup/MarkupAttributePanelFactories.java
@@ -92,7 +92,7 @@ public ApplicationAdvice appliesTo(final IModel<?> model) {
             }
 
             return appliesIf(valueType.isAssignableFrom(
-                    objectAdapter.getSpecification().getCorrespondingClass()) );
+                    objectAdapter.objSpec().getCorrespondingClass()) );
         }
 
         @Override
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/present/ajaxtable/columns/SingularColumn.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/present/ajaxtable/columns/SingularColumn.java
index 52cee17af23..acdfa81610f 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/present/ajaxtable/columns/SingularColumn.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/collection/present/ajaxtable/columns/SingularColumn.java
@@ -51,7 +51,7 @@ protected Component createCellComponent(final String componentId, final DataRowW
         var dataRow = dataRowWkt.getObject();
         var rowElement = dataRow.rowElement();
         var rowElementModel = UiObjectWkt.ofAdapter(rowElement);
-        var property = rowElement.getSpecification().getPropertyElseFail(memberId);
+        var property = rowElement.objSpec().getPropertyElseFail(memberId);
 
         var propertyModel = rowElementModel
                 .getPropertyModel(
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/col/Col.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/col/Col.java
index a8aa86ae540..691e20d72e6 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/col/Col.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/layout/bs/col/Col.java
@@ -225,7 +225,7 @@ private void buildGui() {
         }
 
         final UiObjectWkt objectModel = getModel();
-        var ownerSpec = objectModel.getManagedObject().getSpecification();
+        var ownerSpec = objectModel.getManagedObject().objSpec();
 
         // collection layout data by collection id (the collection's member-id)
         // preserving order, as order matters
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/object/fieldset/PropertyGroup.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/object/fieldset/PropertyGroup.java
index c1ca2e342d7..17add85ce73 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/object/fieldset/PropertyGroup.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/object/fieldset/PropertyGroup.java
@@ -163,7 +163,7 @@ private Can<OneToOneAssociation> getPropertiesNotStaticallyHidden() {
         return _NullSafe.stream(propertyLayouts)
         .filter(propertyLayoutData -> propertyLayoutData.getMetadataError() == null)
         .map(propertyLayoutData ->
-            entity.getSpecification().getProperty(propertyLayoutData.getId())
+            entity.objSpec().getProperty(propertyLayoutData.getId())
             .orElse(null)
         )
         .filter(_NullSafe::isPresent)
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/object/icontitle/ObjectIconAndTitlePanel.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/object/icontitle/ObjectIconAndTitlePanel.java
index dfda33ace8d..0de35be25df 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/object/icontitle/ObjectIconAndTitlePanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/object/icontitle/ObjectIconAndTitlePanel.java
@@ -224,8 +224,8 @@ private TitleRecord determineTitle(final ManagedObject linkedDomainObject) {
         return this.cachedTitle = TitleRecord.builder()
                 .fullTitle(fullTitle)
                 .abbreviatedTitle(titleAbbreviated(fullTitle))
-                .tooltipTitle(_Strings.nullToEmpty(linkedDomainObject.getSpecification().getSingularName()))
-                .tooltipBody(_Strings.nonEmpty(linkedDomainObject.getSpecification().getDescription())
+                .tooltipTitle(_Strings.nullToEmpty(linkedDomainObject.objSpec().getSingularName()))
+                .tooltipBody(_Strings.nonEmpty(linkedDomainObject.objSpec().getDescription())
                         .orElseGet(()->fullTitle))
                 .build();
     }
@@ -268,7 +268,7 @@ private static void guardAgainstNonEmptyAbstractSingular(final ObjectAdapterMode
                 ()->String.format("model for EntityIconAndTitlePanel, "
                         + "when non-empty, must not represent abstract types; "
                         + "however, got an abstract %s for object of type %s",
-                        obj.getSpecification(),
+                        obj.objSpec(),
                         obj.getPojo().getClass().getName()));
     }
 
@@ -278,7 +278,7 @@ private static boolean isNonEmptyAbstractSingular(final ManagedObject obj) {
                 || ManagedObjects.isPacked(obj)) {
             return false;
         }
-        return obj.getSpecification().isAbstract();
+        return obj.objSpec().isAbstract();
     }
 
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/table/CausewayAjaxDataTable.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/table/CausewayAjaxDataTable.java
index 4746dd3fa0f..bbd5562c6fb 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/table/CausewayAjaxDataTable.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/table/CausewayAjaxDataTable.java
@@ -91,7 +91,7 @@ private static String cssClassForRow(final DataRow model) {
             return null;
         }
         var rowElement = model.rowElement();
-        return rowElement.getSpecification().getCssClass(rowElement);
+        return rowElement.objSpec().getCssClass(rowElement);
     }
 
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/unknown/UnknownModelPanel.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/unknown/UnknownModelPanel.java
index abffe8bfe97..a5eabf78b18 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/unknown/UnknownModelPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/unknown/UnknownModelPanel.java
@@ -66,7 +66,7 @@ private void buildMessageForModel(final StringBuilder buf, final IModel<?> model
             var attributeAdapter = attributeModel.getObject();
             if(ManagedObjects.isSpecified(attributeAdapter)) {
                 buf.append(String.format("??? spec=%s, value='%s'",
-                        attributeAdapter.getSpecification(), attributeAdapter.getPojo()));
+                        attributeAdapter.objSpec(), attributeAdapter.getPojo()));
             } else {
                 buf.append("??? scalarAdapter is NULL or UNSPECIFIED");
             }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/actionlink/ActionLink.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/actionlink/ActionLink.java
index 94ca687f976..40f638265f0 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/actionlink/ActionLink.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/components/widgets/actionlink/ActionLink.java
@@ -215,7 +215,7 @@ private void executeWithoutParams() {
 
     private void startDialogWithParams(final AjaxRequestTarget target) {
         var actionModel = this.getActionModel();
-        var actionOwnerSpec = actionModel.getActionOwner().getSpecification();
+        var actionOwnerSpec = actionModel.getActionOwner().objSpec();
         var actionPrompt = ActionPromptProvider
                 .getFrom(this.getPage())
                 .getActionPrompt(actionModel.getPromptStyle(), actionOwnerSpec.getBeanSort());
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/MediatorFactory.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/MediatorFactory.java
index 7b477026256..71f1d451cbb 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/MediatorFactory.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/exec/MediatorFactory.java
@@ -192,7 +192,7 @@ private ManagedObject determineScalarAdapter(
             final @NonNull MetaModelContext mmc,
             final @NonNull ManagedObject resultAdapter) {
 
-        if (resultAdapter.getSpecification().isSingular()) return resultAdapter;
+        if (resultAdapter.objSpec().isSingular()) return resultAdapter;
 
         // will only be a single element
         final Object pojo = _NullSafe