You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2020/09/19 13:34:36 UTC

[isis] 01/03: ISIS-2222: reworking Command and other stuff

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

danhaywood pushed a commit to branch ISIS-2222
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 2194cc18cc04140ad7f836c0103b5c3593aef3ca
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Sun Sep 13 11:40:05 2020 +0100

     ISIS-2222: reworking Command and other stuff
---
 antora/playbooks/site-extensions.yml               |   6 +
 antora/playbooks/site.yml                          |   9 +
 api/adoc/pom.xml                                   |  40 ++
 .../modules/ROOT/partials/component-nav.adoc       |   1 +
 .../applib-ant/examples/annotation/Action.java     |  26 +-
 .../examples/annotation/CommandExecuteIn.java      |  83 ---
 .../examples/annotation/CommandPersistence.java    |  52 --
 .../applib-ant/examples/annotation/Nature.java     |  16 +
 .../applib-ant/examples/annotation/Property.java   |  38 +-
 .../modules/applib-ant/pages/Action/command.adoc   |  20 +-
 .../modules/applib-ant/pages/Property/command.adoc | 194 +------
 .../examples/domain/DomainObjectList.java          |   2 +-
 .../examples/events/domain/ActionDomainEvent.java  |  16 +-
 .../events/domain/PropertyDomainEvent.java         |  24 +-
 .../layout/component/PropertyLayoutData.java       |  12 -
 .../layout/menubars/{Menu.java => HasNamed.java}   |   4 +-
 .../examples/layout/menubars/Menu.java             |   7 +-
 .../examples/layout/menubars/MenuSection.java      |   2 +-
 .../layout/menubars/bootstrap3/BS3MenuSection.java |  12 +
 .../mixins/layout/Object_rebuildMetamodel.java     |  22 +-
 .../applib-classes/examples/util/JaxbAdapters.java | 356 ------------
 .../applib-classes/examples/util/ToString.java     |  17 +-
 .../examples/util/schema/CommandDtoUtils.java      |   4 +
 .../examples/util/schema/CommonDtoUtils.java       |  51 +-
 .../applib-classes/examples/value/Blob.java        |  48 ++
 .../applib-classes/examples/value/Clob.java        |  50 ++
 .../applib-classes/examples/value/HasHtml.java     |   5 -
 .../examples/value/LocalResourcePath.java          |  24 +-
 .../applib-classes/examples/value/Markup.java      |  40 +-
 .../applib-classes/examples/value/Password.java    |  19 +-
 .../roles-mixins-contributees/contributee.adoc     |  12 +-
 .../examples/services/DomainChangeRecord.java      | 155 +++++
 .../DomainChangeRecord_openTargetObject.java       |  61 ++
 .../applib-svc/examples/services/HasUsername.java  |   4 +
 .../services/TransactionScopeListener.java         |   9 +-
 .../background/BackgroundCommandService.java       |  59 --
 .../examples/services/bookmark/Bookmark.java       |   1 +
 .../examples/services/command/Command.java         | 408 +++++---------
 .../examples/services/command/CommandContext.java  |  37 +-
 .../examples/services/command/CommandDefault.java  | 182 ------
 .../services/command/CommandDtoProcessor.java      |   1 -
 .../CommandDtoProcessorForActionAbstract.java      |   4 +-
 .../CommandDtoProcessorForPropertyAbstract.java    |   4 +-
 .../services/command/CommandExecutorService.java   |  15 +-
 .../examples/services/command/CommandService.java  |  92 +++
 .../services/command/spi/CommandService.java       |  65 ---
 .../CommandServiceListener.java}                   |  27 +-
 .../ContentMappingServiceForCommandDto.java        |  45 +-
 .../services/conmap/command/UserDataKeys.java}     |  19 +-
 .../services/exceprecog/ExceptionRecognizer.java   |  31 +-
 .../examples/services/iactn/Interaction.java       |   5 +-
 .../services/iactn/InteractionContext.java         |   5 +-
 .../examples/services/jaxb/JaxbService.java        |  20 +-
 .../examples/services/jaxb/JaxbServiceDefault.java |   4 +-
 .../queryresultscache/QueryResultsCache.java       |   4 +-
 .../examples/services/scratchpad/Scratchpad.java   |  10 +-
 .../examples/services/sudo/SudoService.java        |   9 +-
 .../TableColumnOrderForCollectionTypeAbstract.java |  65 +++
 .../services/wrapper/control/ControlAbstract.java  |  17 +-
 .../services/xactn/TransactionService.java         |  15 -
 .../modules/applib-svc/pages/BookmarkService.adoc  |   1 -
 .../modules/applib-svc/pages/CommandContext.adoc   |  40 +-
 .../modules/applib-svc/pages/CommandService.adoc   |   9 +-
 .../pages/_BackgroundCommandService.adoc           | 107 ----
 .../applib-svc/pages/_BackgroundService.adoc       | 120 ----
 .../pages/_BackgroundService/_Quartz.adoc          | 165 ------
 .../modules/applib-svc/partials/module-nav.adoc    |   4 -
 .../org/apache/isis/applib/IsisModuleApplib.java   |   2 +
 .../org/apache/isis/applib/annotation/Action.java  |  26 +-
 .../isis/applib/annotation/CommandExecuteIn.java   |  83 ---
 .../isis/applib/annotation/CommandPersistence.java |  52 --
 .../apache/isis/applib/annotation/Property.java    |  38 +-
 .../mixins/layout/Object_rebuildMetamodel.java     |  22 +-
 .../isis/applib/services/DomainChangeRecord.java   | 155 +++++
 .../DomainChangeRecord_openTargetObject.java       |  61 ++
 .../apache/isis/applib/services/HasUsername.java   |   4 +
 .../applib/services/TransactionScopeListener.java  |   9 +-
 .../background/BackgroundCommandService.java       |  59 --
 .../isis/applib/services/bookmark/Bookmark.java    |   1 +
 .../isis/applib/services/command/Command.java      | 408 +++++---------
 .../applib/services/command/CommandContext.java    |  25 +-
 .../applib/services/command/CommandDefault.java    | 182 ------
 .../services/command/CommandDtoProcessor.java      |   1 -
 .../CommandDtoProcessorForActionAbstract.java      |   4 +-
 .../CommandDtoProcessorForPropertyAbstract.java    |   4 +-
 .../services/command/CommandExecutorService.java   |  15 +-
 .../applib/services/command/CommandService.java    |  92 +++
 .../applib/services/command/CommandWithDto.java    |  35 --
 .../services/command/spi/CommandService.java       |  65 ---
 .../command/spi/CommandServiceListener.java}       |  25 +-
 .../ContentMappingServiceForCommandDto.java        |  38 +-
 .../services/conmap/command/UserDataKeys.java}     |  19 +-
 .../queryresultscache/QueryResultsCache.java       |   4 +-
 .../applib/services/scratchpad/Scratchpad.java     |  10 +-
 .../isis/applib/services/sudo/SudoService.java     |   9 +-
 .../TableColumnOrderForCollectionTypeAbstract.java |  65 +++
 .../applib/services/xactn/TransactionService.java  |  15 -
 .../java/org/apache/isis/applib/util/ToString.java |  17 +-
 .../isis/applib/util/schema/CommandDtoUtils.java   |   4 +
 .../commons/internal/exceptions/_Exceptions.java   |  14 +
 .../adoc/modules/config/pages/sections/Other.adoc  |   2 +-
 .../adoc/modules/config/pages/sections/_nav.adoc   |   2 +-
 .../modules/config/pages/sections/isis.applib.adoc |  54 +-
 .../pages/sections/isis.core.meta-model.adoc       |   2 +-
 .../isis.core.meta-model.introspector.adoc         |   8 +-
 .../sections/isis.core.meta-model.validator.adoc   |   6 +-
 .../pages/sections/isis.core.runtime-services.adoc |  24 +-
 .../config/pages/sections/isis.core.runtime.adoc   |   4 +-
 .../config/pages/sections/isis.extensions.adoc     | 110 +++-
 .../modules/config/pages/sections/isis.legacy.adoc |   4 +-
 .../isis.persistence.jdo-datanucleus.impl.adoc     |  56 +-
 .../config/pages/sections/isis.security.shiro.adoc |   2 +-
 .../config/pages/sections/isis.testing.adoc        |   2 +-
 .../config/pages/sections/isis.value-types.adoc    |  18 +-
 .../pages/sections/isis.viewer.restfulobjects.adoc |  20 +-
 .../config/pages/sections/isis.viewer.wicket.adoc  |  54 +-
 .../modules/config/pages/sections/resteasy.adoc    |  29 +-
 .../apache/isis/core/config/IsisConfiguration.java | 135 ++++-
 .../command/CommandFacetForActionAnnotation.java   |  14 +-
 ...ommandFacetForActionAnnotationAsConfigured.java |   8 +-
 .../command/CommandFacetFromConfiguration.java     |   9 +-
 ...ctionInvocationFacetForDomainEventAbstract.java | 109 ++--
 .../actions/action/invocation/CommandUtil.java     |  26 +
 .../facets/actions/command/CommandFacet.java       |  18 -
 .../actions/command/CommandFacetAbstract.java      |  38 --
 .../property/PropertyAnnotationFacetFactory.java   |   2 +-
 .../command/CommandFacetForPropertyAnnotation.java |  55 +-
 ...mandFacetForPropertyAnnotationAsConfigured.java |   7 +-
 ...tySetterOrClearFacetForDomainEventAbstract.java | 130 ++---
 .../facets/schema/IsisSchemaValueTypeProvider.java |   2 +-
 .../services/appfeat/ApplicationFeatureId.java     |   4 +-
 .../command/CommandDtoServiceInternal.java         |  17 +-
 .../specloader/specimpl/ObjectActionDefault.java   |  51 +-
 .../specloader/specimpl/ObjectMemberAbstract.java  |  55 +-
 .../specimpl/OneToOneAssociationDefault.java       |  36 +-
 .../metamodel/valuetypes/ValueTypeDefinition.java  |   6 +-
 .../valuetypes/ValueTypeProviderForBuiltin.java    |   7 +-
 .../action/ActionAnnotationFacetFactoryTest.java   |   6 -
 .../ActionAnnotationFacetFactoryTest_Command.java  | 230 +-------
 core/pom.xml                                       |   8 +-
 .../core/runtime/iactn/IsisInteractionFactory.java |  16 +-
 .../template/AbstractIsisInteractionTemplate.java  |  76 ---
 .../transaction/ChangedObjectsService.java         |   1 -
 .../IsisModuleCoreRuntimeServices.java             |   3 -
 .../background/BackgroundCommandExecution.java     |  74 ---
 .../background/CommandExecutionAbstract.java       |  58 --
 .../command/CommandDtoServiceInternalDefault.java  |  28 +-
 .../command/CommandExecutorServiceDefault.java     | 127 +++--
 .../QueryResultsCacheDefault.java                  |  44 +-
 .../scratchpad/ScratchpadDefault.java              |   4 +-
 .../session/IsisInteractionFactoryDefault.java     |  26 +
 .../runtimeservices/sudo/SudoServiceDefault.java   |  14 +-
 .../wrapper/WrapperFactoryDefault.java             |   2 +-
 .../xactn/TransactionServiceSpring.java            |  14 +
 .../WrapperFactoryDefault_wrappedObject_Test.java  |   4 -
 examples/demo/domain/pom.xml                       |  17 +-
 .../src/main/java/demoapp/dom/DemoModule.java      |   5 +-
 .../ActionCommandDisabledMetaAnnotation.java       |   5 +-
 .../Action/command/ActionCommandJdo.java           |  49 +-
 .../Action/command/ActionCommandJdo.layout.xml     |  30 +-
 .../ActionCommandJdo_backgroundCommands.java       |  39 --
 .../ActionCommandJdo_clearBackgroundCommands.java  |  38 --
 .../ActionCommandJdo_clearForegroundCommands.java  |  38 --
 ...ActionCommandJdo_executeBackgroundCommands.java |  39 --
 .../ActionCommandJdo_foregroundCommands.java       |  39 --
 .../spiimpl/CommandServiceSpiForActions.java       |  95 ----
 .../Action/publishing/ActionPublishingJdo.java     |   4 +-
 .../publishing/ActionPublishingJdo.layout.xml      |   2 +-
 ...onPublishingJdo_clearInteractionExecutions.java |  34 --
 .../ActionPublishingJdo_interactionExecutions.java |  39 --
 .../publishing/DomainObjectPublishingJdo.java      |  19 +-
 .../DomainObjectPublishingVm-description.adoc      |   2 +-
 .../DomainObjectPublishingVm_delete.java           |  30 +-
 .../DomainObjectPublishingDisabledJdoEntities.java |   6 +-
 .../DomainObjectPublishingEnabledJdoEntities.java  |   4 +-
 ...tPublishingEnabledMetaAnnotatedJdoEntities.java |   6 +-
 ...shingEnabledMetaAnnotOverriddenJdoEntities.java |   6 +-
 .../DomainObjectPublishingVm_publishedObjects.java |  39 --
 .../Property/publishing/PropertyPublishingJdo.java |   4 +-
 ...tyPublishingJdo_clearInteractionExecutions.java |  34 --
 ...ropertyPublishingJdo_interactionExecutions.java |  40 --
 .../spiimpl/PublisherServiceSpiForProperties.java  |  48 --
 ...tyRegexPatternVm_updateWithParameterLayout.java |   2 +-
 .../RegexPatternEmailComMetaAnnotation.java        |  14 +-
 .../_changes/ExposeCapturedChanges.java            |   9 +
 .../_changes/ExposeCapturedChanges_changes.java    |  35 ++
 .../ExposeCapturedChanges_clear.java}              |  12 +-
 .../PublisherServiceToCaptureChangesInMemory.java} |   4 +-
 .../_commands/ExposePersistedCommands.java         |  54 ++
 .../ExposePersistedCommands_commands.java          |  33 ++
 .../_interactions/ExposeCapturedInteractions.java  |   9 +
 .../ExposeCapturedInteractions_clear.java          |  31 +
 .../ExposeCapturedInteractions_interactions.java   |  35 ++
 .../_interactions/InteractionDtoVm.java            |  62 ++
 .../InteractionDtoVm.layout.xml}                   |   2 +-
 ...isherServiceToCaptureInteractionsInMemory.java} |   4 +-
 .../java/demoapp/dom/homepage/DemoHomePage.java    |  13 +-
 .../types/javalang/booleans/WrapperBooleans.java   |   2 +-
 .../dom/types/javalang/longs/WrapperLongs.java     |   2 +-
 .../jodatime/jodadatetime/vm/JodaDateTimeVm.java   |   9 +-
 .../jodatime/jodalocaldate/vm/JodaLocalDateVm.java |   9 +-
 .../jodalocaldatetime/vm/JodaLocalDateTimeVm.java  |   9 +-
 .../demo/domain/src/main/resources/application.yml |  10 +-
 .../config/application-primary.properties          |   1 +
 .../config/application-secondary.properties        |   5 +
 .../src/main/resources/static/css/application.css  |   3 +
 .../java/demoapp/webapp/vaadin/DemoAppVaadin.java  |   2 +-
 examples/demo/web/pom.xml                          |   6 +
 .../src/main/java/demoapp/web/DemoAppManifest.java |   9 +-
 .../java/demoapp/webapp/wicket/DemoAppWicket.java  |   3 +-
 .../wicket/src/main/resources/log4j2-spring.xml    |   9 +-
 examples/smoketests/pom.xml                        |   2 +-
 .../testdomain/conf/Configuration_headless.java    |   7 +-
 .../adoc/modules/ROOT/partials/component-nav.adoc  |   1 +
 .../command-log/impl/logging-dn-enhance.properties |  29 +
 extensions/core/command-log/impl/pom.xml           |  75 +++
 .../impl/src/main/java/META-INF/persistence.xml    |  19 +
 .../impl/CommandServiceListenerForJdo.java         |  51 +-
 .../impl/IsisModuleExtCommandLogImpl.java          |  69 +++
 .../extensions/commandlog/impl/jdo/CommandJdo.java | 623 +++++++++++++++++++++
 .../impl/jdo/CommandJdo.layout.fallback.xml        | 140 +++++
 .../extensions/commandlog/impl/jdo/CommandJdo.png  | Bin 0 -> 582 bytes
 .../commandlog/impl/jdo/CommandJdoRepository.java  | 383 +++++++++++++
 .../impl/jdo/CommandJdo_childCommands.java         |  53 ++
 .../impl/jdo/CommandJdo_openResultObject.java      |  73 +++
 .../commandlog/impl/jdo/CommandJdo_retry.java      |  63 +++
 .../impl/jdo/CommandJdo_siblingCommands.java       |  62 ++
 .../commandlog/impl/jdo/ReplayState.java           |  36 +-
 .../impl/mixins/HasUniqueId_command.java           |  61 ++
 .../mixins/HasUsername_recentCommandsByUser.java   |  45 ++
 .../impl/mixins/Object_recentCommands.java         |  59 ++
 .../commandlog/impl/mixins/T_recent.java           |  50 ++
 .../commandlog/impl/ui/CommandServiceMenu.java     | 108 ++++
 .../commandlog/impl/util/BigDecimalUtils.java      |  32 ++
 .../commandlog/impl/util/StringUtils.java          |  17 +
 .../impl/util/StringUtils_trimmed_Test.java        |  28 +
 .../core/command-log}/pom.xml                      |  26 +-
 .../adoc/antora.yml                                |   2 +-
 .../adoc/modules/command-replay/nav.adoc           |  23 +-
 .../adoc/modules/command-replay/pages/about.adoc   |  24 +-
 .../command-replay/partials/module-nav.adoc        |   5 +
 extensions/core/command-replay/impl/pom.xml        |  80 +++
 .../impl/IsisModuleExtCommandReplayImpl.java       | 129 +++++
 .../commandreplay/impl/SecondaryStatus.java        |  10 +
 .../commandreplay/impl/StatusException.java        |  14 +
 .../impl/analysis/CommandReplayAnalyser.java       |  14 +
 .../analysis/CommandReplayAnalyserException.java   |  65 +++
 .../impl/analysis/CommandReplayAnalyserResult.java |  53 ++
 .../analysis/CommandReplayAnalysisService.java     |  46 ++
 .../impl/clock/TickingClockService.java            | 127 +++++
 .../executor/CommandExecutorServiceWithTime.java   |  97 ++++
 .../commandreplay/impl/fetch/CommandFetcher.java   | 147 +++++
 .../commandreplay/impl/fetch/PrimaryConfig.java    |  38 ++
 .../commandreplay/impl/fetch/SecondaryConfig.java  |  32 ++
 .../impl/job/ReplicateAndReplayJob.java            |  93 +++
 .../impl/job/SecondaryStatusData.java              |  36 ++
 .../job/callables/IsTickingClockInitialized.java   |  22 +
 .../job/callables/ReplicateAndRunCommands.java     | 152 +++++
 .../impl/mixins/CommandJdo_download.java           |  49 ++
 .../impl/mixins/CommandJdo_exclude.java            |  46 ++
 .../impl/mixins/CommandJdo_openOnPrimary.java      |  57 ++
 .../impl/mixins/CommandJdo_replayNext.java         | 106 ++++
 .../impl/mixins/CommandJdo_replayQueue.java        |  47 ++
 .../impl/spi/ReplayCommandExecutionController.java |  25 +
 .../impl/ui/CommandReplayOnPrimaryService.java     | 180 ++++++
 .../impl/ui/CommandReplayOnSecondaryService.java   |  80 +++
 .../impl/fetch/ReplicateAndReplayJob_Test.java     |  35 ++
 .../core/command-replay}/pom.xml                   |  42 +-
 .../flyway/adoc/modules/flyway/pages/about.adoc    |   2 +-
 extensions/core/model-annotation/adoc/antora.yml   |   2 +-
 .../adoc/modules/model-annotation/nav.adoc         |  23 +-
 .../adoc/modules/model-annotation/pages/about.adoc |  24 +-
 .../model-annotation/partials/module-nav.adoc      |   5 +
 .../{model-annotation => quartz}/adoc/antora.yml   |   0
 .../examples/DemoIsisInteractionTemplate.java      |  28 +
 .../adoc/modules/quartz/examples/DemoJob.java      |  37 ++
 .../examples/DemoJobQuartzConfigurerModule.java    |  69 +++
 .../core/quartz/adoc/modules/quartz/nav.adoc       |  23 +-
 .../quartz/adoc/modules/quartz/pages/about.adoc    |  38 +-
 .../adoc/modules/quartz/partials/module-nav.adoc   |   5 +
 extensions/core/quartz/impl/pom.xml                |  72 +++
 .../extensions/quartz/IsisModuleExtQuartzImpl.java |  15 +
 .../quartz/context/JobExecutionData.java           |  36 ++
 .../spring/AutowiringSpringBeanJobFactory.java     |  30 +
 .../restclient => extensions/core/quartz}/pom.xml  |  19 +-
 extensions/pom.xml                                 |  24 +-
 .../isis/legacy/applib/DomainObjectContainer.java  |   3 +
 .../background/BackgroundCommandService2.java      |  30 -
 .../services/background/BackgroundService.java     |  60 --
 .../services/background/BackgroundService2.java    |  28 -
 .../services/eventbus/ActionDomainEvent.java       |   3 +
 .../services/eventbus/CollectionDomainEvent.java   |   3 +
 .../services/eventbus/PropertyDomainEvent.java     |   4 +
 .../org/apache/isis/legacy/applib/value/Color.java |   3 +
 .../apache/isis/legacy/applib/value/Magnitude.java |   4 +
 .../org/apache/isis/legacy/applib/value/Money.java |   4 +
 .../isis/legacy/applib/value/Percentage.java       |   4 +
 mappings/jaxrsclient/{api => applib}/build.gradle  |   2 +-
 mappings/jaxrsclient/{api => applib}/pom.xml       |  10 +-
 .../applib/IsisModuleExtJaxRsClientApplib.java}    |  13 +-
 .../jaxrsclient/applib/client/JaxRsClient.java}    |  38 +-
 .../jaxrsclient/applib/client/JaxRsResponse.java}  |  10 +-
 mappings/jaxrsclient/{api => impl}/pom.xml         |  19 +-
 .../impl/IsisModuleExtJaxRsClientImpl.java}        |   4 +-
 .../impl/client/JaxRsClientDefault.java            | 133 +++++
 .../impl/client/JaxRsResponseDefault.java          |  24 +
 mappings/jaxrsclient/pom.xml                       |   3 +-
 mappings/jaxrsclient/{api => testlib}/pom.xml      |  13 +-
 .../impl/IsisModuleExtJaxRsClientImpl.java}        |   4 +-
 .../jaxrsclient/impl/JaxRsClientDefault.java       | 148 +++++
 .../extensions/jaxrsclient/impl/JaxRsResponse.java |  54 ++
 mappings/pom.xml                                   |  10 +-
 mappings/restclient/{api => applib}/build.gradle   |   2 +-
 mappings/restclient/{api => applib}/pom.xml        |   4 +-
 .../restclient/ActionParameterListBuilder.java     |   0
 .../restclient/IsisModuleExtRestClient.java        |   0
 .../isis/extensions/restclient/ResponseDigest.java |   0
 .../isis/extensions/restclient/RestfulClient.java  |   0
 .../extensions/restclient/RestfulClientConfig.java |   0
 .../restclient/RestfulClientException.java         |   0
 .../isis/extensions/restclient/ScalarValueDto.java |   0
 .../restclient/auth/BasicAuthFilter.java           |   0
 .../restclient/log/RestfulLoggingFilter.java       |   0
 mappings/restclient/pom.xml                        |   2 +-
 .../service/JdoPersistenceLifecycleService.java    |  13 +-
 .../IsisBookmarkConverter.java}                    |  17 +-
 .../IsisLocalResourcePathConverter.java            |   2 +-
 .../{ => applib}/IsisMarkupConverter.java          |   2 +-
 .../{ => applib}/IsisPasswordConverter.java        |   2 +-
 .../v2/IsisChangesDtoConverter.java}               |  16 +-
 .../v2/IsisCommandDtoConverter.java}               |  17 +-
 .../v2/IsisInteractionDtoConverter.java}           |  15 +-
 .../v2/IsisOidDtoConverter.java}                   |  21 +-
 .../{ => applib}/ByteArrayBlobRdbmsMapping.java    |   2 +-
 .../valuetypes/{ => applib}/IsisBlobMapping.java   |   2 +-
 .../valuetypes/{ => applib}/IsisClobMapping.java   |   2 +-
 .../persistence/IsisPersistenceSessionJdoBase.java |   2 +-
 .../persistence/PersistenceSession5.java           |  77 +--
 .../datanucleus-5/src/main/resources/plugin.xml    |  96 +++-
 .../applib/teardown/TeardownFixtureAbstract.java   |  91 ++-
 testing/integtestsupport/applib/pom.xml            |  57 ++
 .../applib/IsisIntegrationTestAbstract.java        |  26 +-
 valuetypes/pom.xml                                 |   5 -
 .../resources/DomainObjectResourceServerside.java  |  24 +-
 .../resources/DomainServiceResourceServerside.java |  21 +-
 .../viewer/resources/ResourceAbstract.java         |   9 -
 .../wicket/ui/app/logout/LogoutHandlerWkt.java     |   6 +-
 .../CollectionContentsAsAjaxTablePanel.java        |   1 -
 .../components/scalars/bookmark/BookmarkPanel.java |  26 +-
 .../scalars/bookmark/BookmarkPanelFactory.java     |  28 +-
 .../scalars/markup/MarkupPanelFactories.java       |   5 +-
 .../ui/components/scalars/oiddto/OidDtoPanel.java  |  26 +-
 .../scalars/oiddto/OidDtoPanelFactory.java         |  25 +-
 .../wicket/ui/panels/FormExecutorDefault.java      |  12 +-
 .../wicket/viewer/mixins/Object_clearHints.java    |  36 +-
 .../ComponentFactoryRegistrarDefault.java          |   7 +
 356 files changed, 7940 insertions(+), 5394 deletions(-)

diff --git a/antora/playbooks/site-extensions.yml b/antora/playbooks/site-extensions.yml
index 9d17401..c4aef14 100644
--- a/antora/playbooks/site-extensions.yml
+++ b/antora/playbooks/site-extensions.yml
@@ -44,8 +44,14 @@ content:
       start_path: extensions/core/command-log/adoc # extensions
       branches: HEAD
     - url: .
+      start_path: extensions/core/command-replay/adoc # extensions
+      branches: HEAD
+    - url: .
       start_path: extensions/core/flyway/adoc # userguide
       branches: HEAD
+    - url: .
+      start_path: extensions/core/model-annotation/adoc # extensions
+      branches: HEAD
 
     - url: .
       start_path: extensions/security/secman/adoc # security
diff --git a/antora/playbooks/site.yml b/antora/playbooks/site.yml
index 0721fe0..da0f7e4 100644
--- a/antora/playbooks/site.yml
+++ b/antora/playbooks/site.yml
@@ -109,8 +109,17 @@ content:
       start_path: extensions/core/command-log/adoc # extensions
       branches: HEAD
     - url: .
+      start_path: extensions/core/command-replay/adoc # extensions
+      branches: HEAD
+    - url: .
       start_path: extensions/core/flyway/adoc # userguide
       branches: HEAD
+    - url: .
+      start_path: extensions/core/model-annotation/adoc # extensions
+      branches: HEAD
+    - url: .
+      start_path: extensions/core/quartz/adoc # userguide
+      branches: HEAD
 
     - url: .
       start_path: extensions/security/audit-trail/adoc # security
diff --git a/api/adoc/pom.xml b/api/adoc/pom.xml
new file mode 100644
index 0000000..a097e3a
--- /dev/null
+++ b/api/adoc/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.isis.core</groupId>
+        <artifactId>isis</artifactId>
+        <version>2.0.0-SNAPSHOT</version>
+        <relativePath>../../core/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>isis-api-adoc</artifactId>
+
+    <name>Apache Isis Core - API Documentation</name>
+    <description>
+        User guide and reference guide.
+        This pom.xml is just for convenience to allow the documentation to be
+        opened independently of the entire project.  It is not part of the
+        main hierarchy.
+    </description>
+
+</project>
diff --git a/api/adoc/userguide/modules/ROOT/partials/component-nav.adoc b/api/adoc/userguide/modules/ROOT/partials/component-nav.adoc
index f35ad96..227dd73 100644
--- a/api/adoc/userguide/modules/ROOT/partials/component-nav.adoc
+++ b/api/adoc/userguide/modules/ROOT/partials/component-nav.adoc
@@ -4,5 +4,6 @@ include::userguide:btb:partial$module-nav.adoc[]
 * Extensions
 
 include::userguide:flyway:partial$module-nav.adoc[]
+include::userguide:quartz:partial$module-nav.adoc[]
 
 
diff --git a/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/Action.java b/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/Action.java
index c73d945..12583cd 100644
--- a/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/Action.java
+++ b/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/Action.java
@@ -27,8 +27,7 @@ import java.lang.annotation.Target;
 
 import org.apache.isis.applib.events.domain.ActionDomainEvent;
 import org.apache.isis.applib.services.command.CommandDtoProcessor;
-import org.apache.isis.applib.services.command.CommandWithDto;
-import org.apache.isis.applib.services.command.spi.CommandService;
+import org.apache.isis.applib.services.command.CommandService;
 import org.apache.isis.applib.services.conmap.command.ContentMappingServiceForCommandDto;
 import org.apache.isis.applib.services.conmap.command.ContentMappingServiceForCommandsDto;
 import org.apache.isis.applib.value.Blob;
@@ -99,29 +98,6 @@ public @interface Action {
 
     // end::refguide[]
     /**
-     * How the {@link org.apache.isis.applib.services.command.Command Command} object provided by the
-     * {@link org.apache.isis.applib.services.command.CommandContext CommandContext} domain service should be persisted.
-     */
-    // tag::refguide[]
-    CommandPersistence commandPersistence()                         // <.>
-            default CommandPersistence.PERSISTED;
-
-    // end::refguide[]
-    /**
-     * How the command/action should be executed.
-     *
-     * <p>
-     * If the corresponding {@link org.apache.isis.applib.services.command.Command Command} object is persisted,
-     * then its {@link org.apache.isis.applib.services.command.Command#getExecuteIn() invocationType} property
-     * will be set to this value.
-     * </p>
-     */
-    // tag::refguide[]
-    CommandExecuteIn commandExecuteIn()                             // <.>
-            default CommandExecuteIn.FOREGROUND;
-
-    // end::refguide[]
-    /**
      * The {@link CommandDtoProcessor} to process this command's DTO.
      *
      * <p>
diff --git a/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/CommandExecuteIn.java b/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/CommandExecuteIn.java
deleted file mode 100644
index 14afaed..0000000
--- a/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/CommandExecuteIn.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.applib.annotation;
-
-/**
- * Whether a command should be executed immediately and synchronously in the foreground or rather should only be
- * persisted (such that it can be executed asynchronously in the background by some other mechanism).
- *
- * <p>
- *     Note: this enum is <i>not</i> an inner class of the {@link org.apache.isis.applib.annotation.Action} annotation
- *     because in the future we may also support commands for {@link org.apache.isis.applib.annotation.Property} and
- *     {@link org.apache.isis.applib.annotation.Collection}.
- * </p>
- */
-// tag::refguide[]
-public enum CommandExecuteIn {
-    // end::refguide[]
-    /**
-     * Execute synchronously in the &quot;foreground&quot;, wait for the results.
-     */
-    // tag::refguide[]
-    FOREGROUND,
-    // end::refguide[]
-    /**
-     * Execute &quot;asynchronously&quot; through the {@link org.apache.isis.applib.services.background.BackgroundCommandService}, returning (if possible) the
-     * persisted {@link org.apache.isis.applib.services.command.Command command} object as a placeholder to the
-     * result.
-     */
-    // tag::refguide[]
-    BACKGROUND,
-    // end::refguide[]
-    /**
-     * For commands that are replicated from a master onto a slave and are to be replayed (typically using the same
-     * mechanism as "regular" background commands, eg a background job).
-     *
-     * <p>
-     *     For framework use, not intended to be used in application code.
-     * </p>
-     */
-    // tag::refguide[]
-    REPLAYABLE,
-    // end::refguide[]
-    /**
-     * For commands that have been excluded and will not run.
-     * These are typically for a replayable command that has hit an exception (which normally would prevent any further
-     * replayable commands from being replayed) and which the administrator has decided to skip.
-     */
-    // tag::refguide[]
-    EXCLUDED
-    // end::refguide[]
-    ;
-
-    public boolean isForeground() { return this == FOREGROUND; }
-    public boolean isBackground() { return this == BACKGROUND; }
-    public boolean isReplayable() { return this == REPLAYABLE; }
-    public boolean isExcluded() { return this == EXCLUDED; }
-
-    public static class Type {
-        private Type() {}
-        public static class Meta {
-            public static final int MAX_LEN = 10;
-            private Meta() {}
-        }
-    }
-    // tag::refguide[]
-}
-// end::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/CommandPersistence.java b/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/CommandPersistence.java
deleted file mode 100644
index 7f7000a..0000000
--- a/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/CommandPersistence.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.applib.annotation;
-
-/**
- * Whether the command should be persisted.
- */
-// tag::refguide[]
-public enum CommandPersistence {
-
-    // end::refguide[]
-    /**
-     * (If the configured {@link org.apache.isis.applib.services.command.spi.CommandService} supports it), indicates that the
-     * {@link org.apache.isis.applib.services.command.Command Command} object should be persisted.
-     */
-    // tag::refguide[]
-    PERSISTED,
-    // end::refguide[]
-    /**
-     * (If the configured {@link org.apache.isis.applib.services.command.spi.CommandService} supports it), indicates that the
-     * {@link org.apache.isis.applib.services.command.Command Command} object should only be persisted if
-     * another service, such as the {@link org.apache.isis.applib.services.background.BackgroundCommandService}, hints that it should.
-     */
-    // tag::refguide[]
-    IF_HINTED,
-    // end::refguide[]
-    /**
-     * (Even if the configured {@link org.apache.isis.applib.services.command.spi.CommandService} supports it), indicates that the
-     * {@link org.apache.isis.applib.services.command.Command Command} object should <i>not</i> be persisted (even if
-     * another service, such as the {@link org.apache.isis.applib.services.background.BackgroundCommandService}, hints that it should).
-     */
-    // tag::refguide[]
-    NOT_PERSISTED
-
-}
-// end::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/Nature.java b/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/Nature.java
index b044747..8ac77a7 100644
--- a/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/Nature.java
+++ b/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/Nature.java
@@ -55,6 +55,22 @@ public enum Nature {
      */
     // tag::refguide[]
     JDO_ENTITY,
+    
+    // end::refguide[]
+    /**
+     * A domain entity whose persistence is managed internally by Isis, using JPA as the persistence implementation.
+     * Domain entities are considered to be part of the domain model layer.
+     *
+     * <p>
+     *     Domain entities are considered to be part of the domain model layer.
+     * </p>
+     *
+     * <p>
+     *    Currently implies no additional semantics other than documentation.
+     * </p>
+     */
+    // tag::refguide[]
+    JPA_ENTITY,
 
     // end::refguide[]
     /**
diff --git a/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/Property.java b/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/Property.java
index ac40f2d..5393e2c 100644
--- a/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/Property.java
+++ b/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/Property.java
@@ -27,8 +27,6 @@ import java.lang.annotation.Target;
 
 import org.apache.isis.applib.events.domain.PropertyDomainEvent;
 import org.apache.isis.applib.services.command.CommandDtoProcessor;
-import org.apache.isis.applib.services.command.CommandWithDto;
-import org.apache.isis.applib.services.command.spi.CommandService;
 import org.apache.isis.applib.services.conmap.command.ContentMappingServiceForCommandDto;
 import org.apache.isis.applib.services.conmap.command.ContentMappingServiceForCommandsDto;
 import org.apache.isis.applib.spec.Specification;
@@ -52,7 +50,8 @@ public @interface Property {
 
     // end::refguide[]
     /**
-     * Whether the property edit should be reified into a {@link org.apache.isis.applib.services.command.Command} object.
+     * Whether the property edit should be reified into a
+     * {@link org.apache.isis.applib.services.command.Command} object.
      */
     // tag::refguide[]
     CommandReification command()                                // <.>
@@ -60,39 +59,10 @@ public @interface Property {
 
     // end::refguide[]
     /**
-     * How the {@link org.apache.isis.applib.services.command.Command Command} object provided by the
-     * {@link org.apache.isis.applib.services.command.CommandContext CommandContext} domain service should be persisted.
-     */
-    // tag::refguide[]
-    CommandPersistence commandPersistence()                     // <.>
-            default CommandPersistence.PERSISTED;
-
-    // end::refguide[]
-    /**
-     * How the command/property edit should be executed.
-     *
-     * <p>
-     * If the corresponding {@link org.apache.isis.applib.services.command.Command Command} object is persisted,
-     * then its {@link org.apache.isis.applib.services.command.Command#getExecuteIn() invocationType} property
-     * will be set to this value.
-     * </p>
-     */
-    // tag::refguide[]
-    CommandExecuteIn commandExecuteIn()                         // <.>
-            default CommandExecuteIn.FOREGROUND;
-
-    // end::refguide[]
-    /**
      * The {@link CommandDtoProcessor} to process this command's DTO.
      *
      * <p>
-     *     Specifying a processor requires that the implementation of {@link CommandService} provides a
-     *     custom implementation of {@link org.apache.isis.applib.services.command.Command} that additional extends
-     *     from {@link CommandWithDto}.
-     * </p>
-     *
-     * <p>
-     *     Tprocessor itself is used by {@link ContentMappingServiceForCommandDto} and
+     *     The processor itself is used by {@link ContentMappingServiceForCommandDto} and
      *     {@link ContentMappingServiceForCommandsDto} to dynamically transform the DTOs.
      * </p>
      */
@@ -210,7 +180,7 @@ public @interface Property {
      *
      * <p>
      *     For properties the default value, {@link org.apache.isis.applib.annotation.Optionality#DEFAULT}, usually
-     *     means that the property is required unless it has been overridden by {@link javax.jdo.annotations.Column}
+     *     means that the property is required unless it has been overridden by <code>javax.jdo.annotations.Column</code>
      *     with its <code>javax.jdo.annotations.Column#allowsNull()</code> attribute set to true.
      * </p>
      */
diff --git a/api/applib/src/main/adoc/modules/applib-ant/pages/Action/command.adoc b/api/applib/src/main/adoc/modules/applib-ant/pages/Action/command.adoc
index 5a35003..5ef273a 100644
--- a/api/applib/src/main/adoc/modules/applib-ant/pages/Action/command.adoc
+++ b/api/applib/src/main/adoc/modules/applib-ant/pages/Action/command.adoc
@@ -4,6 +4,7 @@
 :Notice: 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 ag [...]
 :page-partial:
 
+CAUTION: TODO - v2, this documentation is not out of date.
 
 Every action invocation (and property edit for that matter) is automatically reified into a concrete `Command` object.
 The `@Action(command=..., commandXxx=...)` attributes provide hints for the persistence of that `Command` object, and the subsequent processing of that persisted command.
@@ -277,25 +278,6 @@ For persisted commands, the `commandExecuteIn` attribute determines whether the
 
 WARNING: TODO: v2 - background execution has temporarily been removed, will be reinstated for v2.0.
 
-//Background execution means that the command is not executed immediately, but is available for a configured xref:refguide:applib-svc:_BackgroundCommandService.adoc[`BackgroundCommandService`] to execute, eg by way of an in-memory scheduler such as Quartz.
-//See xref:userguide:btb:about.adoc#BackgroundCommandExecution[here] for further information on this topic.
-
-//For example:
-//
-//[source,java]
-//----
-//public class Order {
-//    @Action(
-//        command=CommandReification.ENABLED,
-//        commandExecuteIn=CommandExecuteIn.BACKGROUND
-//    )
-//    public Invoice generateInvoice(...) { /* ... */ }
-//}
-//----
-//
-//will result in the `Command` being persisted but its execution deferred to a background execution mechanism.
-//The returned object from this action invocation is the persisted `Command` itself.
-
 
 
 
diff --git a/api/applib/src/main/adoc/modules/applib-ant/pages/Property/command.adoc b/api/applib/src/main/adoc/modules/applib-ant/pages/Property/command.adoc
index 7562660..40f23a3 100644
--- a/api/applib/src/main/adoc/modules/applib-ant/pages/Property/command.adoc
+++ b/api/applib/src/main/adoc/modules/applib-ant/pages/Property/command.adoc
@@ -4,6 +4,7 @@
 :Notice: 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 ag [...]
 :page-partial:
 
+CAUTION: TODO - v2 to update, has been simplified.
 
 Every property edit (and action invocation for that matter) is automatically reified into a concrete `Command` object.
 The `@Property(command=..., commandXxx=...)` attributes provide hints for the persistence of that `Command` object, and the subsequent processing of that persisted command.
@@ -16,8 +17,6 @@ The annotation works with (and is influenced by the behaviour of) a number of do
 
 * xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`]
 * xref:refguide:applib-svc:CommandService.adoc[`CommandService`]
-//* xref:refguide:applib-svc:BackgroundService.adoc[`BackgroundService`] and
-//* xref:refguide:applib-svc:_BackgroundCommandService.adoc[`BackgroundCommandService`]
 
 
 Each property edit is automatically reified by the xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] service into a `Command` object, capturing details of the target object, the property, the proposed new value for the property, the user, a timestamp and so on.
@@ -25,197 +24,6 @@ Each property edit is automatically reified by the xref:refguide:applib-svc:Comm
 If an appropriate `CommandService` is configured (for example using xref:extensions:command-log:about.adoc[Command Log] extension module), then the `Command` itself is persisted.
 
 By default, actions are invoked in directly in the thread of the invocation.
-//If there is an implementation of `BackgroundCommandService` (as the (non-ASF) link:https://platform.incode.org[Incode Platform^]'s command module does provide), then this means in turn that the `BackgroundService` can be used by the domain object code to programmatically create background ``Command``s.
-
-//[NOTE]
-//====
-//If background ``Command``s are used, then an external scheduler, using xref:userguide:btb:about.adoc#BackgroundCommandExecution[headless access], must also be configured.
-//====
-
-== `command()` and `commandPersistence()`
-
-The `command()` and `commandPersistence() attributes work together to determine whether a command will actually be persisted.
-There inter-relationship is somewhat complex, so is probably best explained by way of examples:
-
-[cols="1a,1a,1a,1a,2a", options="header"]
-|===
-
-| `command()`
-|`isis.services.
-command.properties` config property
-| `command
-Persistence()`
-| action dirties objects?
-| is command persisted?
-
-| `ENABLED`
-| (any)
-| `PERSISTED`
-| (either)
-| yes
-
-| `ENABLED`
-| (any)
-| `IF_HINTED`
-| no
-| no
-
-| `ENABLED`
-| (any)
-| `IF_HINTED`
-| yes
-| yes
-
-| `ENABLED`
-| (any)
-| `NOT_PERSISTED`
-| (any)
-| no
-
-| `AS_CONFIGURED`
-| `all`
-| `PERSISTED`
-| no
-| yes
-
-| `AS_CONFIGURED`
-| `all`
-| `IF_HINTED`
-| no
-| no
-
-| `AS_CONFIGURED`
-| `all`
-| `IF_HINTED`
-| yes
-| yes
-
-| `AS_CONFIGURED`
-| `all`
-| `NOT_PERSISTED`
-| (any)
-| no
-
-| `AS_CONFIGURED`
-| `none`
-| `PERSISTED`
-| no
-| no (!)
-
-| `AS_CONFIGURED`
-| `none`
-| `PERSISTED`
-| yes
-| yes
-
-| `AS_CONFIGURED`
-| `none`
-| `IF_HINTED`
-| no
-| no
-
-| `AS_CONFIGURED`
-| `none`
-| `IF_HINTED`
-| yes
-| yes
-
-| `AS_CONFIGURED`
-| `none`
-| `NOT_PERSISTED`
-| no
-| no
-
-| `AS_CONFIGURED`
-| `none`
-| `NOT_PERSISTED`
-| yes
-| yes (!)
-
-| `DISABLED`
-| (any)
-| `PERSISTED`
-| no
-| no (!)
-
-| `DISABLED`
-| (any)
-| `PERSISTED`
-| yes
-| yes
-
-| `DISABLED`
-| (any)
-| `IF_HINTED`
-| no
-| no
-
-| `DISABLED`
-| (any)
-| `IF_HINTED`
-| yes
-| yes
-
-| `DISABLED`
-| (any)
-| `NOT_PERSISTED`
-| no
-| no
-
-| `DISABLED`
-| (any)
-| `NOT_PERSISTED`
-| yes
-| yes (!)
-
-|===
-
-For example:
-
-[source,java]
-----
-public class Order {
-    @Property(
-        command=CommandReification.ENABLED,
-        commandPersistence=CommandPersistence.PERSISTED
-    )
-    public Product getProduct() { /* ... */ }
-    public void setProduct(Product p) { /* ... */ }
-}
-----
-
-As can be seen, whether a command is actually persisted does not always follow the value of the `commandPersistence` attribute.
-This is because the `command` attribute actually determines whether any command metadata for the action is captured within the framework's internal metamodel.
-If `command` is `DISABLED` or does not otherwise apply due to the action's declared semantics, then the framework decides to persist a command based solely on whether the action dirtied any objects (as if `commandPersistence()` was set to `IF_HINTED`).
-
-
-
-== `commandExecuteIn()`
-
-For persisted commands, the `commandExecuteIn` attribute determines whether the `Command` should be executed in the foreground (the default) or executed in the background.
-
-WARNING: TODO: v2 - background execution has temporarily been removed, will be reinstated for v2.0.
-
-//Background execution means that the command is not executed immediately, but is available for a configured xref:refguide:applib-svc:_BackgroundCommandService.adoc[`BackgroundCommandService`] to execute, eg by way of an in-memory scheduler such as Quartz.
-//See xref:userguide:btb:about.adoc#BackgroundCommandExecution[here] for further information on this topic.
-
-//For example:
-//
-//[source,java]
-//----
-//public class Order {
-//    @Property(
-//        command=CommandReification.ENABLED,
-//        commandExecuteIn=CommandExecuteIn.BACKGROUND
-//    )
-//    public Product getProduct() { /* ... */ }
-//    public void setProduct(Product p) { /* ... */ }
-//}
-//----
-//
-//will result in the `Command` being persisted but its execution deferred to a background execution mechanism.
-//The returned object from this property edit is the persisted `Command` itself.
-
 
 
 
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/domain/DomainObjectList.java b/api/applib/src/main/adoc/modules/applib-classes/examples/domain/DomainObjectList.java
index 2a13734..7dfe76a 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/domain/DomainObjectList.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/domain/DomainObjectList.java
@@ -35,7 +35,7 @@ import org.apache.isis.applib.annotation.Editing;
 import org.apache.isis.applib.annotation.Nature;
 import org.apache.isis.applib.annotation.Optionality;
 import org.apache.isis.applib.annotation.Property;
-import org.apache.isis.applib.jaxbadapters.PersistentEntitiesAdapter;
+import org.apache.isis.applib.jaxb.PersistentEntitiesAdapter;
 
 @XmlRootElement(name = "list")
 @XmlType(
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/events/domain/ActionDomainEvent.java b/api/applib/src/main/adoc/modules/applib-classes/examples/events/domain/ActionDomainEvent.java
index b935e91..f891fe1 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/events/domain/ActionDomainEvent.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/events/domain/ActionDomainEvent.java
@@ -25,6 +25,7 @@ import org.apache.isis.applib.util.ObjectContracts;
 import org.apache.isis.applib.util.ToString;
 
 import lombok.Getter;
+import lombok.Setter;
 
 // tag::refguide[]
 public abstract class ActionDomainEvent<S> extends AbstractDomainEvent<S> {
@@ -110,9 +111,16 @@ public abstract class ActionDomainEvent<S> extends AbstractDomainEvent<S> {
     /**
      * The arguments being used to invoke the action; populated at {@link Phase#VALIDATE} and subsequent phases
      * (but null for {@link Phase#HIDE hidden} and {@link Phase#DISABLE disable} phases).
+     *
+     * <p>
+     *     The argument values can also be modified by event handlders
+     *     during the {@link Phase#EXECUTING} phase.    The new value must be
+     *     the same type as the expected value; the framework performs
+     *     no sanity checks.
+     * </p>
      */
     // tag::refguide[]
-    @Getter
+    @Getter @Setter
     private List<Object> arguments;
 
     // end::refguide[]
@@ -166,12 +174,6 @@ public abstract class ActionDomainEvent<S> extends AbstractDomainEvent<S> {
     public void setMixedIn(final Object mixedIn) {
         this.mixedIn = mixedIn;
     }
-    /**
-     * Not API - set by the framework.
-     */
-    public void setArguments(List<Object> arguments) {
-        this.arguments = arguments;
-    }
 
 
     private static final ToString<ActionDomainEvent<?>> toString = ObjectContracts.<ActionDomainEvent<?>>
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/events/domain/PropertyDomainEvent.java b/api/applib/src/main/adoc/modules/applib-classes/examples/events/domain/PropertyDomainEvent.java
index 405f4a5..1dbf127 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/events/domain/PropertyDomainEvent.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/events/domain/PropertyDomainEvent.java
@@ -22,6 +22,7 @@ import org.apache.isis.applib.util.ObjectContracts;
 import org.apache.isis.applib.util.ToString;
 
 import lombok.Getter;
+import lombok.Setter;
 
 // tag::refguide[]
 public abstract class PropertyDomainEvent<S,T> extends AbstractDomainEvent<S> {
@@ -69,32 +70,27 @@ public abstract class PropertyDomainEvent<S,T> extends AbstractDomainEvent<S> {
      * (but null for {@link org.apache.isis.applib.events.domain.AbstractDomainEvent.Phase#HIDE hidden} and {@link org.apache.isis.applib.events.domain.AbstractDomainEvent.Phase#DISABLE disable} phases).
      */
     // tag::refguide[]
-    @Getter
+    @Getter @Setter
     private T oldValue;
 
     // end::refguide[]
     /**
      * The proposed (post-modification) value of the property; populated at {@link org.apache.isis.applib.events.domain.AbstractDomainEvent.Phase#VALIDATE} and subsequent phases
      * (but null for {@link org.apache.isis.applib.events.domain.AbstractDomainEvent.Phase#HIDE hidden} and {@link org.apache.isis.applib.events.domain.AbstractDomainEvent.Phase#DISABLE disable} phases).
+     *
+     * <p>
+     *     The proposed new value can also be modified by event handlers
+     *     during the {@link Phase#EXECUTING} phase.  The new value must be
+     *     the same type as the expected value; the framework performs
+     *     no sanity checks.
+     * </p>
      */
     // tag::refguide[]
-    @Getter
+    @Getter @Setter
     private T newValue;
 
     // end::refguide[]
-    /**
-     * Not API; for framework use only.
-     */
-    public void setOldValue(T oldValue) {
-        this.oldValue = oldValue;
-    }
 
-    /**
-     * Not API; for framework use only.
-     */
-    public void setNewValue(T newValue) {
-        this.newValue = newValue;
-    }
 
 
     private static final ToString<PropertyDomainEvent<?,?>> toString =
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/layout/component/PropertyLayoutData.java b/api/applib/src/main/adoc/modules/applib-classes/examples/layout/component/PropertyLayoutData.java
index 817a6aa..a56700b 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/layout/component/PropertyLayoutData.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/layout/component/PropertyLayoutData.java
@@ -211,18 +211,6 @@ HasCssClass, HasDescribedAs, HasHidden, HasNamed  {
     }
 
 
-    @XmlAttribute(required = false)
-    public Boolean getUnchanging() {
-        return getRepainting() != null ? getRepainting() == Repainting.NO_REPAINT : null;
-    }
-
-    public void setUnchanging(Boolean unchanging) {
-        if(getRepainting() == null && unchanging != null) {
-            setRepainting(unchanging ? Repainting.NO_REPAINT : Repainting.REPAINT);
-        }
-    }
-
-
     private Repainting repainting;
 
     @XmlAttribute(required = false)
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/Menu.java b/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/HasNamed.java
similarity index 96%
copy from api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/Menu.java
copy to api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/HasNamed.java
index cbb2797..6627d86 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/Menu.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/HasNamed.java
@@ -20,9 +20,9 @@ package org.apache.isis.applib.layout.menubars;
 
 import org.apache.isis.applib.annotation.Programmatic;
 
-public interface Menu {
+public interface HasNamed {
 
     @Programmatic
     String getNamed();
-
+    
 }
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/Menu.java b/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/Menu.java
index cbb2797..68789ba 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/Menu.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/Menu.java
@@ -18,11 +18,6 @@
  */
 package org.apache.isis.applib.layout.menubars;
 
-import org.apache.isis.applib.annotation.Programmatic;
-
-public interface Menu {
-
-    @Programmatic
-    String getNamed();
+public interface Menu extends HasNamed {
 
 }
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/MenuSection.java b/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/MenuSection.java
index d3f2873..feacaf0 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/MenuSection.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/MenuSection.java
@@ -23,7 +23,7 @@ import java.util.List;
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.layout.component.ServiceActionLayoutData;
 
-public interface MenuSection {
+public interface MenuSection extends HasNamed {
 
     @Programmatic
     List<ServiceActionLayoutData> getServiceActions();
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/bootstrap3/BS3MenuSection.java b/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/bootstrap3/BS3MenuSection.java
index 79716b6..1e563b8 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/bootstrap3/BS3MenuSection.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/bootstrap3/BS3MenuSection.java
@@ -36,6 +36,7 @@ import org.apache.isis.applib.layout.menubars.MenuSection;
 @XmlType(
         name = "section"
         , propOrder = {
+                "named",
                 "serviceActions"
         }
         )
@@ -46,7 +47,18 @@ public class BS3MenuSection implements MenuSection, Serializable, ServiceActionL
     public BS3MenuSection() {
     }
 
+    private String named;
 
+    @Override
+    @XmlElement(required = false)
+    public String getNamed() {
+        return named;
+    }
+
+    public void setNamed(String named) {
+        this.named = named;
+    }
+    
     private List<ServiceActionLayoutData> serviceActions = new ArrayList<>();
 
     // no wrapper
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/mixins/layout/Object_rebuildMetamodel.java b/api/applib/src/main/adoc/modules/applib-classes/examples/mixins/layout/Object_rebuildMetamodel.java
index 506c7a7..c68f875 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/mixins/layout/Object_rebuildMetamodel.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/mixins/layout/Object_rebuildMetamodel.java
@@ -22,7 +22,6 @@ import javax.inject.Inject;
 
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.ActionLayout;
-import org.apache.isis.applib.annotation.CommandPersistence;
 import org.apache.isis.applib.annotation.Contributed;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.Mixin;
@@ -33,7 +32,15 @@ import org.apache.isis.applib.services.metamodel.MetaModelService;
 
 import lombok.RequiredArgsConstructor;
 
-@Mixin(method="act") 
+@Action(
+        domainEvent = Object_rebuildMetamodel.ActionDomainEvent.class,
+        semantics = SemanticsOf.IDEMPOTENT,
+        restrictTo = RestrictTo.PROTOTYPING
+)
+@ActionLayout(
+        cssClassFa = "fa-sync",
+        position = ActionLayout.Position.PANEL
+)
 @RequiredArgsConstructor
 public class Object_rebuildMetamodel {
 
@@ -42,17 +49,6 @@ public class Object_rebuildMetamodel {
     public static class ActionDomainEvent
     extends org.apache.isis.applib.IsisModuleApplib.ActionDomainEvent<Object_rebuildMetamodel> {}
 
-    @Action(
-            domainEvent = ActionDomainEvent.class,
-            semantics = SemanticsOf.IDEMPOTENT,
-            commandPersistence = CommandPersistence.NOT_PERSISTED,
-            restrictTo = RestrictTo.PROTOTYPING
-            )
-    @ActionLayout(
-            contributed = Contributed.AS_ACTION,
-            cssClassFa = "fa-sync",
-            position = ActionLayout.Position.PANEL
-            )
     @MemberOrder(name = MixinConstants.METADATA_LAYOUT_GROUPNAME, sequence = "800.1")
     public Object act() {
         metaModelService.rebuild(holder.getClass());
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/util/JaxbAdapters.java b/api/applib/src/main/adoc/modules/applib-classes/examples/util/JaxbAdapters.java
deleted file mode 100644
index 66c53e3..0000000
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/util/JaxbAdapters.java
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.applib.util;
-
-import java.nio.charset.StandardCharsets;
-import java.time.Duration;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.OffsetDateTime;
-import java.time.OffsetTime;
-import java.time.Period;
-import java.time.ZonedDateTime;
-import java.util.Base64;
-
-import javax.activation.MimeType;
-import javax.activation.MimeTypeParseException;
-import javax.xml.bind.annotation.adapters.XmlAdapter;
-
-import org.apache.isis.applib.value.Blob;
-import org.apache.isis.applib.value.Clob;
-import org.apache.isis.applib.value.Markup;
-import org.apache.isis.core.commons.internal.base._Bytes;
-import org.apache.isis.core.commons.internal.base._Strings;
-
-/**
- * Provides JAXB XmlAdapters for Java built-in temporal types. 
- * Others types might be added, if convenient. 
- * <p>
- * 
- * Example:<pre>
- * &#64;XmlElement &#64;XmlJavaTypeAdapter(JaxbAdapters.LocalDateAdapter.class)
- * &#64;Getter &#64;Setter private LocalDate javaLocalDate;
- * </pre>
- * 
- *  
- * @since 2.0
- */
-public final class JaxbAdapters {
-    
-    // -- BYTES
-    
-    /**
-     * Uses compression. (thread-safe)
-     */
-    public static final class BytesAdapter extends XmlAdapter<String, byte[]> {
-
-        @Override
-        public byte[] unmarshal(String v) throws Exception {
-            return _Bytes.ofCompressedUrlBase64.apply(_Strings.toBytes(v, StandardCharsets.UTF_8));
-        }
-
-        @Override
-        public String marshal(byte[] v) throws Exception {
-            return _Strings.ofBytes(_Bytes.asCompressedUrlBase64.apply(v), StandardCharsets.UTF_8);
-        }
-
-    }
-
-    // -- MARKUP
-
-    public static final class MarkupAdapter extends XmlAdapter<String, Markup> {
-
-        /**
-         * Is threadsafe, see <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Encoder.html">JDK8 javadocs</a>
-         */
-        private final Base64.Encoder encoder = Base64.getEncoder();
-        /**
-         * Is threadsafe, see <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Decoder.html">JDK8 javadocs</a>
-         */
-        private final Base64.Decoder decoder = Base64.getDecoder(); // is thread-safe ?
-
-        @Override
-        public Markup unmarshal(String v) throws Exception {
-            if(v==null) {
-                return null;
-            }
-            final String html = _Strings.ofBytes(decoder.decode(v), StandardCharsets.UTF_8);
-            return new Markup(html);
-        }
-
-        @Override
-        public String marshal(Markup v) throws Exception {
-            if(v==null) {
-                return null;
-            }
-            final String html = v.asHtml();
-            return encoder.encodeToString(_Strings.toBytes(html, StandardCharsets.UTF_8));
-        }
-    }
-
-    // -- BLOB
-
-    /**
-     * (thread-safe)
-     * @implNote see also BlobValueSemanticsProvider
-     */
-    public static final class BlobAdapter extends XmlAdapter<String, Blob> {
-        
-        private final BytesAdapter bytesAdapter = new BytesAdapter(); // thread-safe
-
-        @Override
-        public Blob unmarshal(String data) throws Exception {
-            if(data==null) {
-                return null;
-            }
-            final int colonIdx = data.indexOf(':');
-            final String name  = data.substring(0, colonIdx);
-            final int colon2Idx  = data.indexOf(":", colonIdx+1);
-            final String mimeTypeBase = data.substring(colonIdx+1, colon2Idx);
-            final String payload = data.substring(colon2Idx+1);
-            final byte[] bytes = bytesAdapter.unmarshal(payload);
-            try {
-                return new Blob(name, new MimeType(mimeTypeBase), bytes);
-            } catch (MimeTypeParseException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        @Override
-        public String marshal(Blob blob) throws Exception {
-            if(blob==null) {
-                return null;
-            }
-            return new StringBuilder()
-            .append(blob.getName())
-            .append(':')
-            .append(blob.getMimeType().getBaseType())
-            .append(':')
-            .append(bytesAdapter.marshal(blob.getBytes()))
-            .toString();
-        }
-
-    }
-    
-    // -- CLOB
-
-    /**
-     * (thread-safe)
-     * @implNote see also ClobValueSemanticsProvider
-     */
-    public static final class ClobAdapter extends XmlAdapter<String, Clob> {
-        
-        private final BytesAdapter bytesAdapter = new BytesAdapter(); // thread-safe
-
-        @Override
-        public Clob unmarshal(String data) throws Exception {
-            if(data==null) {
-                return null;
-            }
-            final int colonIdx = data.indexOf(':');
-            final String name  = data.substring(0, colonIdx);
-            final int colon2Idx  = data.indexOf(":", colonIdx+1);
-            final String mimeTypeBase = data.substring(colonIdx+1, colon2Idx);
-            final String payload = data.substring(colon2Idx+1);
-            final byte[] bytes = bytesAdapter.unmarshal(payload);
-            try {
-                return new Clob(name, new MimeType(mimeTypeBase), new String(bytes, StandardCharsets.UTF_8));
-            } catch (MimeTypeParseException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        @Override
-        public String marshal(Clob clob) throws Exception {
-            if(clob==null) {
-                return null;
-            }
-            return new StringBuilder()
-            .append(clob.getName())
-            .append(':')
-            .append(clob.getMimeType().getBaseType())
-            .append(':')
-            .append(bytesAdapter.marshal(clob.getChars().toString().getBytes(StandardCharsets.UTF_8)))
-            .toString();
-        }
-
-    }
-
-
-
-    // -- TEMPORAL VALUE TYPES
-
-    public static final class DateAdapter extends XmlAdapter<String, java.util.Date> {
-
-        @Override
-        public java.util.Date unmarshal(String v) throws Exception {
-            return v!=null ? new java.util.Date(Long.parseLong(v)) : null;
-        }
-
-        @Override
-        public String marshal(java.util.Date v) throws Exception {
-            return v!=null ? Long.toString(v.getTime()) : null;
-        }
-
-    }
-
-    public static final class SqlDateAdapter extends XmlAdapter<String, java.sql.Date> {
-
-        @Override
-        public java.sql.Date unmarshal(String v) throws Exception {
-            return v!=null ? java.sql.Date.valueOf(v) : null;
-        }
-
-        @Override
-        public String marshal(java.sql.Date v) throws Exception {
-            return v!=null ? v.toString() : null;
-        }
-
-    }
-
-    public static final class SqlTimestampAdapter extends XmlAdapter<String, java.sql.Timestamp> {
-
-        @Override
-        public java.sql.Timestamp unmarshal(String v) throws Exception {
-            return v!=null ? new java.sql.Timestamp(Long.parseLong(v)) : null;
-        }
-
-        @Override
-        public String marshal(java.sql.Timestamp v) throws Exception {
-            return v!=null ? Long.toString(v.getTime()) : null;
-        }
-
-    }
-
-    public static final class LocalTimeAdapter extends XmlAdapter<String, LocalTime> {
-
-        @Override
-        public LocalTime unmarshal(String v) throws Exception {
-            return v!=null ? LocalTime.parse(v) : null;
-        }
-
-        @Override
-        public String marshal(LocalTime v) throws Exception {
-            return v!=null ? v.toString() : null;
-        }
-
-    }
-    
-    public static final class LocalDateAdapter extends XmlAdapter<String, LocalDate> {
-
-        @Override
-        public LocalDate unmarshal(String v) throws Exception {
-            return v!=null ? LocalDate.parse(v) : null;
-        }
-
-        @Override
-        public String marshal(LocalDate v) throws Exception {
-            return v!=null ? v.toString() : null;
-        }
-
-    }
-
-    public static final class LocalDateTimeAdapter extends XmlAdapter<String, LocalDateTime> {
-
-        @Override
-        public LocalDateTime unmarshal(String v) throws Exception {
-            return v!=null ? LocalDateTime.parse(v) : null;
-        }
-
-        @Override
-        public String marshal(LocalDateTime v) throws Exception {
-            return v!=null ? v.toString() : null;
-        }
-
-    }
-    
-    public static final class OffsetTimeAdapter extends XmlAdapter<String, OffsetTime> {
-
-        @Override
-        public OffsetTime unmarshal(String v) throws Exception {
-            return v!=null ? OffsetTime.parse(v) : null;
-        }
-
-        @Override
-        public String marshal(OffsetTime v) throws Exception {
-            return v!=null ? v.toString() : null;
-        }
-
-    }
-
-    public static final class OffsetDateTimeAdapter extends XmlAdapter<String, OffsetDateTime> {
-
-        @Override
-        public OffsetDateTime unmarshal(String v) throws Exception {
-            return v!=null ? OffsetDateTime.parse(v) : null;
-        }
-
-        @Override
-        public String marshal(OffsetDateTime v) throws Exception {
-            return v!=null ? v.toString() : null;
-        }
-
-    }
-    
-    public static final class ZonedDateTimeAdapter extends XmlAdapter<String, ZonedDateTime> {
-
-        @Override
-        public ZonedDateTime unmarshal(String v) throws Exception {
-            return v!=null ? ZonedDateTime.parse(v) : null;
-        }
-
-        @Override
-        public String marshal(ZonedDateTime v) throws Exception {
-            return v!=null ? v.toString() : null;
-        }
-
-    }
-    
-    public static final class DurationAdapter extends XmlAdapter<String, Duration> {
-
-        @Override
-        public Duration unmarshal(String v) throws Exception {
-            return v!=null ? Duration.parse(v) : null;
-        }
-
-        @Override
-        public String marshal(Duration v) throws Exception {
-            return v!=null ? v.toString() : null;
-        }
-
-    }
-    
-    public static final class PeriodAdapter extends XmlAdapter<String, Period> {
-
-        @Override
-        public Period unmarshal(String v) throws Exception {
-            return v!=null ? Period.parse(v) : null;
-        }
-
-        @Override
-        public String marshal(Period v) throws Exception {
-            return v!=null ? v.toString() : null;
-        }
-
-    }
-    
-    
-
-}
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/util/ToString.java b/api/applib/src/main/adoc/modules/applib-classes/examples/util/ToString.java
index a11a431..8893742 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/util/ToString.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/util/ToString.java
@@ -41,7 +41,7 @@ public class ToString<T> {
         return new ToString<>(name, getter, false);
     }
 
-    public static <T> ToString<T> toStringOmmitIfAbsent(String name, Function<? super T, ?> getter) {
+    public static <T> ToString<T> toStringOmitIfAbsent(String name, Function<? super T, ?> getter) {
         Objects.requireNonNull(name);
         Objects.requireNonNull(getter);
         return new ToString<>(name, getter, true);
@@ -49,10 +49,10 @@ public class ToString<T> {
 
     private final List<String> names = _Lists.newArrayList();
     private final List<Function<? super T, ?>> getters = _Lists.newArrayList();
-    private final BitSet ommitIfAbsent = new BitSet();
+    private final BitSet omitIfAbsent = new BitSet();
 
-    private ToString(String name, Function<? super T, ?> getter, boolean ommitIfAbsent) {
-        addBit(ommitIfAbsent);
+    private ToString(String name, Function<? super T, ?> getter, boolean omitIfAbsent) {
+        addBit(omitIfAbsent);
         names.add(name);
         getters.add(getter);
     }
@@ -66,7 +66,7 @@ public class ToString<T> {
         return this;
     }
 
-    public ToString<T> thenToStringOmmitIfAbsent(String name, Function<? super T, ?> getter){
+    public ToString<T> thenToStringOmitIfAbsent(String name, Function<? super T, ?> getter){
         Objects.requireNonNull(name);
         Objects.requireNonNull(getter);
         addBit(true);
@@ -95,13 +95,12 @@ public class ToString<T> {
 
         return String.format("%s{%s}",
 
-                //ommitIfAbsent.toString(),
                 target.getClass().getSimpleName(),
 
                 getters.stream()
                 .peek(__->index[0]++)
                 .map(getter->getter.apply(target))
-                .filter(value->value!=null || !ommitIfAbsent.get(index[0]))
+                .filter(value->value!=null || !omitIfAbsent.get(index[0]))
                 .map(valueToStringFunction)
                 .map(valueLiteral->names.get(index[0])+"="+valueLiteral)
                 .collect(Collectors.joining(", "))
@@ -114,9 +113,9 @@ public class ToString<T> {
     private void addBit(boolean bit) {
         final int index = names.size();
         if(bit) {
-            ommitIfAbsent.set(index);
+            omitIfAbsent.set(index);
         } else {
-            ommitIfAbsent.clear(index);
+            omitIfAbsent.clear(index);
         }
     }
 
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/util/schema/CommandDtoUtils.java b/api/applib/src/main/adoc/modules/applib-classes/examples/util/schema/CommandDtoUtils.java
index bb7a815..9b6c93b0 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/util/schema/CommandDtoUtils.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/util/schema/CommandDtoUtils.java
@@ -63,6 +63,10 @@ public final class CommandDtoUtils {
         }
     }
 
+    public static CommandDto clone(final CommandDto commandDto) {
+        return fromXml(toXml(commandDto));
+    }
+
     public static CommandDto fromXml(final String xml) {
         return fromXml(new StringReader(xml));
     }
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/util/schema/CommonDtoUtils.java b/api/applib/src/main/adoc/modules/applib-classes/examples/util/schema/CommonDtoUtils.java
index 7038580..b50f6e9 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/util/schema/CommonDtoUtils.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/util/schema/CommonDtoUtils.java
@@ -33,6 +33,9 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.function.Function;
 
+import org.apache.isis.applib.jaxb.JavaSqlXMLGregorianCalendarMarshalling;
+import org.apache.isis.applib.jaxb.JavaTimeXMLGregorianCalendarMarshalling;
+import org.apache.isis.applib.jaxb.JodaTimeXMLGregorianCalendarMarshalling;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.value.Blob;
@@ -220,57 +223,57 @@ public final class CommonDtoUtils {
         }
         case LOCAL_DATE: {
             final LocalDate argValue = (LocalDate) pojo;
-            valueDto.setLocalDate(XmlCalendarFactory.create(argValue));
+            valueDto.setLocalDate(JavaTimeXMLGregorianCalendarMarshalling.toXMLGregorianCalendar2(argValue));
             return valueDto;
         }
         case LOCAL_TIME: {
             final LocalTime argValue = (LocalTime) pojo;
-            valueDto.setLocalTime(XmlCalendarFactory.create(argValue));
+            valueDto.setLocalTime(JavaTimeXMLGregorianCalendarMarshalling.toXMLGregorianCalendar2(argValue));
             return valueDto;
         }
         case LOCAL_DATE_TIME: {
             final LocalDateTime argValue = (LocalDateTime) pojo;
-            valueDto.setLocalDateTime(XmlCalendarFactory.create(argValue));
+            valueDto.setLocalDateTime(JavaTimeXMLGregorianCalendarMarshalling.toXMLGregorianCalendar2(argValue));
             return valueDto;
         }
         case OFFSET_DATE_TIME: {
             final OffsetDateTime argValue = (OffsetDateTime) pojo;
-            valueDto.setOffsetDateTime(XmlCalendarFactory.create(argValue));
+            valueDto.setOffsetDateTime(JavaTimeXMLGregorianCalendarMarshalling.toXMLGregorianCalendar2(argValue));
             return valueDto;
         }
         case OFFSET_TIME: {
             final OffsetTime argValue = (OffsetTime) pojo;
-            valueDto.setOffsetTime(XmlCalendarFactory.create(argValue));
+            valueDto.setOffsetTime(JavaTimeXMLGregorianCalendarMarshalling.toXMLGregorianCalendar2(argValue));
             return valueDto;
         }
         case ZONED_DATE_TIME: {
             final ZonedDateTime argValue = (ZonedDateTime) pojo;
-            valueDto.setZonedDateTime(XmlCalendarFactory.create(argValue));
+            valueDto.setZonedDateTime(JavaTimeXMLGregorianCalendarMarshalling.toXMLGregorianCalendar2(argValue));
             return valueDto;
         }
         case JODA_DATE_TIME: {
             final org.joda.time.DateTime argValue = (org.joda.time.DateTime) pojo;
-            valueDto.setOffsetDateTime(JodaDateTimeXMLGregorianCalendarAdapter.print(argValue));
+            valueDto.setOffsetDateTime(JodaTimeXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(argValue));
             return valueDto;
         }
         case JODA_LOCAL_DATE_TIME: {
             final org.joda.time.LocalDateTime argValue = (org.joda.time.LocalDateTime) pojo;
-            valueDto.setLocalDateTime(JodaLocalDateTimeXMLGregorianCalendarAdapter.print(argValue));
+            valueDto.setLocalDateTime(JodaTimeXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(argValue));
             return valueDto;
         }
         case JODA_LOCAL_DATE: {
             final org.joda.time.LocalDate argValue = (org.joda.time.LocalDate) pojo;
-            valueDto.setLocalDate(JodaLocalDateXMLGregorianCalendarAdapter.print(argValue));
+            valueDto.setLocalDate(JodaTimeXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(argValue));
             return valueDto;
         }
         case JODA_LOCAL_TIME: {
             final org.joda.time.LocalTime argValue = (org.joda.time.LocalTime) pojo;
-            valueDto.setLocalTime(JodaLocalTimeXMLGregorianCalendarAdapter.print(argValue));
+            valueDto.setLocalTime(JodaTimeXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(argValue));
             return valueDto;
         }
         case JAVA_SQL_TIMESTAMP: {
             final java.sql.Timestamp argValue = (java.sql.Timestamp) pojo;
-            valueDto.setTimestamp(JavaSqlTimestampXmlGregorianCalendarAdapter.print(argValue));
+            valueDto.setTimestamp(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(argValue));
             return valueDto;
         }
         case ENUM: {
@@ -298,7 +301,6 @@ public final class CommonDtoUtils {
             return valueDto;
         }
         case BLOB: {
-
             final Blob blob = (Blob) pojo;
             if(blob != null) {
                 final BlobDto blobDto = new BlobDto();
@@ -374,35 +376,34 @@ public final class CommonDtoUtils {
         case CHAR:
             final String aChar = valueDto.getChar();
             if(_Strings.isNullOrEmpty(aChar)) { return null; }
-            return (Object)aChar.charAt(0);
+            return aChar.charAt(0);
         case BIG_DECIMAL:
             return valueDto.getBigDecimal();
         case BIG_INTEGER:
             return valueDto.getBigInteger();
          // JAVA TIME    
         case LOCAL_DATE:
-            return XmlCalendarFactory.toLocalDate(valueDto.getLocalDate());
+            return JavaTimeXMLGregorianCalendarMarshalling.toLocalDate(valueDto.getLocalDate());
         case LOCAL_TIME:
-            return XmlCalendarFactory.toLocalTime(valueDto.getLocalTime());
+            return JavaTimeXMLGregorianCalendarMarshalling.toLocalTime(valueDto.getLocalTime());
         case LOCAL_DATE_TIME:
-            return XmlCalendarFactory.toLocalDateTime(valueDto.getLocalDateTime());
+            return JavaTimeXMLGregorianCalendarMarshalling.toLocalDateTime(valueDto.getLocalDateTime());
         case OFFSET_DATE_TIME:
-            return XmlCalendarFactory.toOffsetDateTime(valueDto.getOffsetDateTime());
+            return JavaTimeXMLGregorianCalendarMarshalling.toOffsetDateTime(valueDto.getOffsetDateTime());
         case OFFSET_TIME:
-            return XmlCalendarFactory.toOffsetTime(valueDto.getOffsetTime());
+            return JavaTimeXMLGregorianCalendarMarshalling.toOffsetTime(valueDto.getOffsetTime());
         case ZONED_DATE_TIME:
-            return XmlCalendarFactory.toZonedDateTime(valueDto.getZonedDateTime());
+            return JavaTimeXMLGregorianCalendarMarshalling.toZonedDateTime(valueDto.getZonedDateTime());
         case JAVA_SQL_TIMESTAMP:
-            return JavaSqlTimestampXmlGregorianCalendarAdapter.parse(valueDto.getTimestamp());
-        // JODA
+            return JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(valueDto.getTimestamp());
         case JODA_DATE_TIME:
-            return JodaDateTimeXMLGregorianCalendarAdapter.parse(valueDto.getOffsetDateTime());
+            return JodaTimeXMLGregorianCalendarMarshalling.toDateTime(valueDto.getOffsetDateTime());
         case JODA_LOCAL_DATE:
-            return JodaLocalDateXMLGregorianCalendarAdapter.parse(valueDto.getLocalDate());
+            return JodaTimeXMLGregorianCalendarMarshalling.toLocalDate(valueDto.getLocalDate());
         case JODA_LOCAL_DATE_TIME:
-            return JodaLocalDateTimeXMLGregorianCalendarAdapter.parse(valueDto.getLocalDateTime());
+            return JodaTimeXMLGregorianCalendarMarshalling.toLocalDateTime(valueDto.getLocalDateTime());
         case JODA_LOCAL_TIME:
-            return JodaLocalTimeXMLGregorianCalendarAdapter.parse(valueDto.getLocalTime());
+            return JodaTimeXMLGregorianCalendarMarshalling.toLocalTime(valueDto.getLocalTime());
         case ENUM:
             final EnumDto enumDto = valueDto.getEnum();
             final String enumType = enumDto.getEnumType();
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/value/Blob.java b/api/applib/src/main/adoc/modules/applib-classes/examples/value/Blob.java
index 028aa33..3e66c9d 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/value/Blob.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/value/Blob.java
@@ -25,13 +25,21 @@ import java.util.Arrays;
 import java.util.Objects;
 
 import javax.activation.MimeType;
+import javax.activation.MimeTypeParseException;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
+import org.apache.isis.applib.annotation.Value;
+import org.apache.isis.applib.jaxb.PrimitiveJaxbAdapters;
 import org.apache.isis.core.commons.internal.base._Strings;
 
 import lombok.val;
 
 // tag::refguide[]
 // end::refguide[]
+@Value(semanticsProviderName =
+        "org.apache.isis.core.metamodel.facets.value.blobs.BlobValueSemanticsProvider")
+@XmlJavaTypeAdapter(Blob.JaxbToStringAdapter.class)   // for JAXB view model support
 public final class Blob implements NamedWithMimeType {
 
     /**
@@ -149,4 +157,44 @@ public final class Blob implements NamedWithMimeType {
         return getName() + " [" + getMimeType().getBaseType() + "]: " + getBytes().length + " bytes";
     }
 
+    /**
+     * (thread-safe)
+     * @implNote see also BlobValueSemanticsProvider
+     */
+    public static final class JaxbToStringAdapter extends XmlAdapter<String, Blob> {
+
+        private final PrimitiveJaxbAdapters.BytesAdapter bytesAdapter = new PrimitiveJaxbAdapters.BytesAdapter(); // thread-safe
+
+        @Override
+        public Blob unmarshal(String data) throws Exception {
+            if(data==null) {
+                return null;
+            }
+            final int colonIdx = data.indexOf(':');
+            final String name  = data.substring(0, colonIdx);
+            final int colon2Idx  = data.indexOf(":", colonIdx+1);
+            final String mimeTypeBase = data.substring(colonIdx+1, colon2Idx);
+            final String payload = data.substring(colon2Idx+1);
+            final byte[] bytes = bytesAdapter.unmarshal(payload);
+            try {
+                return new Blob(name, new MimeType(mimeTypeBase), bytes);
+            } catch (MimeTypeParseException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        @Override
+        public String marshal(Blob blob) throws Exception {
+            if(blob==null) {
+                return null;
+            }
+            String s = blob.getName() +
+                    ':' +
+                    blob.getMimeType().getBaseType() +
+                    ':' +
+                    bytesAdapter.marshal(blob.getBytes());
+            return s;
+        }
+
+    }
 }
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/value/Clob.java b/api/applib/src/main/adoc/modules/applib-classes/examples/value/Clob.java
index e1baa9d..d9cf898 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/value/Clob.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/value/Clob.java
@@ -21,16 +21,25 @@ package org.apache.isis.applib.value;
 
 import java.io.IOException;
 import java.io.Writer;
+import java.nio.charset.StandardCharsets;
 import java.util.Objects;
 
 import javax.activation.MimeType;
+import javax.activation.MimeTypeParseException;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
+import org.apache.isis.applib.annotation.Value;
+import org.apache.isis.applib.jaxb.PrimitiveJaxbAdapters;
 import org.apache.isis.core.commons.internal.base._Strings;
 
 import lombok.val;
 
 // tag::refguide[]
 // end::refguide[]
+@Value(semanticsProviderName =
+        "org.apache.isis.core.metamodel.facets.value.clobs.ClobValueSemanticsProvider")
+@XmlJavaTypeAdapter(Clob.JaxbToStringAdapter.class)   // for JAXB view model support
 public final class Clob implements NamedWithMimeType {
 
     private static final long serialVersionUID = 8694189924062378527L;
@@ -142,4 +151,45 @@ public final class Clob implements NamedWithMimeType {
         return getName() + " [" + getMimeType().getBaseType() + "]: " + getChars().length() + " chars";
     }
 
+    /**
+     * (thread-safe)
+     * @implNote see also ClobValueSemanticsProvider
+     */
+    public static final class JaxbToStringAdapter extends XmlAdapter<String, Clob> {
+
+        private final PrimitiveJaxbAdapters.BytesAdapter bytesAdapter = new PrimitiveJaxbAdapters.BytesAdapter(); // thread-safe
+
+        @Override
+        public Clob unmarshal(String data) throws Exception {
+            if(data==null) {
+                return null;
+            }
+            final int colonIdx = data.indexOf(':');
+            final String name  = data.substring(0, colonIdx);
+            final int colon2Idx  = data.indexOf(":", colonIdx+1);
+            final String mimeTypeBase = data.substring(colonIdx+1, colon2Idx);
+            final String payload = data.substring(colon2Idx+1);
+            final byte[] bytes = bytesAdapter.unmarshal(payload);
+            try {
+                return new Clob(name, new MimeType(mimeTypeBase), new String(bytes, StandardCharsets.UTF_8));
+            } catch (MimeTypeParseException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        @Override
+        public String marshal(Clob clob) throws Exception {
+            if(clob==null) {
+                return null;
+            }
+            return new StringBuilder()
+            .append(clob.getName())
+            .append(':')
+            .append(clob.getMimeType().getBaseType())
+            .append(':')
+            .append(bytesAdapter.marshal(clob.getChars().toString().getBytes(StandardCharsets.UTF_8)))
+            .toString();
+        }
+
+    }
 }
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/value/HasHtml.java b/api/applib/src/main/adoc/modules/applib-classes/examples/value/HasHtml.java
index 2905098..ecb6fec 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/value/HasHtml.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/value/HasHtml.java
@@ -19,11 +19,6 @@
 
 package org.apache.isis.applib.value;
 
-import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
-
-import org.apache.isis.applib.annotation.Value;
-import org.apache.isis.applib.util.JaxbAdapters;
-
 // tag::refguide[]
 // end::refguide[]
 public interface HasHtml {
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/value/LocalResourcePath.java b/api/applib/src/main/adoc/modules/applib-classes/examples/value/LocalResourcePath.java
index a0eb7c6..47523bc 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/value/LocalResourcePath.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/value/LocalResourcePath.java
@@ -23,6 +23,8 @@ import java.io.Serializable;
 import java.net.URISyntaxException;
 
 import javax.annotation.Nonnull;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
 import org.apache.isis.applib.annotation.Value;
 
@@ -33,8 +35,11 @@ import lombok.NonNull;
  */
 // tag::refguide[]
 // end::refguide[]
-@Value(semanticsProviderName = "org.apache.isis.core.metamodel.facets.value.localrespath.LocalResourcePathValueSemanticsProvider")
+@Value(semanticsProviderName =
+        "org.apache.isis.core.metamodel.facets.value.localrespath.LocalResourcePathValueSemanticsProvider")
+@XmlJavaTypeAdapter(LocalResourcePath.JaxbToStringAdapter.class)   // for JAXB view model support
 public final class LocalResourcePath implements Serializable {
+
     private static final long serialVersionUID = 1L;
     @NonNull private final String path;
 
@@ -65,7 +70,7 @@ public final class LocalResourcePath implements Serializable {
         if(obj==null) {
             return false;
         }
-        return (obj instanceof LocalResourcePath) ?	isEqualTo((LocalResourcePath)obj) : false;
+        return (obj instanceof LocalResourcePath) && isEqualTo((LocalResourcePath) obj);
     }
     
     @Override
@@ -90,9 +95,20 @@ public final class LocalResourcePath implements Serializable {
             // used for syntax testing
             new java.net.URI("http://localhost/"+path);
         } catch (URISyntaxException e) {
-            throw new IllegalArgumentException("the given local path has an invalid syntax: '"+path+"'", e);
+            throw new IllegalArgumentException(String.format("the given local path has an invalid syntax: '%s'", path), e);
         }
-
     }
 
+
+    public static class JaxbToStringAdapter extends XmlAdapter<String, LocalResourcePath> {
+        @Override
+        public LocalResourcePath unmarshal(String path) {
+            return path != null ? new LocalResourcePath(path) : null;
+        }
+
+        @Override
+        public String marshal(LocalResourcePath localResourcePath) {
+            return localResourcePath != null ? localResourcePath.getPath() : null;
+        }
+    }
 }
\ No newline at end of file
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/value/Markup.java b/api/applib/src/main/adoc/modules/applib-classes/examples/value/Markup.java
index 774b148..478d3b4 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/value/Markup.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/value/Markup.java
@@ -19,10 +19,15 @@
 
 package org.apache.isis.applib.value;
 
+import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
 import org.apache.isis.applib.annotation.Value;
-import org.apache.isis.applib.util.JaxbAdapters;
+import org.apache.isis.core.commons.internal.base._Strings;
 
 /**
  * Immutable value type holding pre-rendered HTML.
@@ -30,11 +35,12 @@ import org.apache.isis.applib.util.JaxbAdapters;
  */
 // tag::refguide[]
 // end::refguide[]
-@Value(semanticsProviderName =
+@Value(semanticsProviderName = 
         "org.apache.isis.core.metamodel.facets.value.markup.MarkupValueSemanticsProvider")
-@XmlJavaTypeAdapter(JaxbAdapters.MarkupAdapter.class)   // for JAXB view model support
-public class Markup implements HasHtml {   // TODO: should be final
+@XmlJavaTypeAdapter(Markup.JaxbToStringAdapter.class)   // for JAXB view model support
+public class Markup implements HasHtml, Serializable {   // TODO: should be final
 
+    private static final long serialVersionUID = 1L;
     private final String html;
 
     public Markup() {
@@ -78,4 +84,30 @@ public class Markup implements HasHtml {   // TODO: should be final
         return "Markup[length="+html.length()+", html="+html+"]";
     }
 
+    public static final class JaxbToStringAdapter extends XmlAdapter<String, Markup> {
+
+        /**
+         * Is threadsafe, see <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Encoder.html">JDK8 javadocs</a>
+         */
+        private final Base64.Encoder encoder = Base64.getEncoder();
+        /**
+         * Is threadsafe, see <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Decoder.html">JDK8 javadocs</a>
+         */
+        private final Base64.Decoder decoder = Base64.getDecoder(); // is thread-safe ?
+
+        @Override
+        public Markup unmarshal(String v) throws Exception {
+            return v != null
+                    ? new Markup(_Strings.ofBytes(decoder.decode(v), StandardCharsets.UTF_8))
+                    : null;
+        }
+
+        @Override
+        public String marshal(Markup v) throws Exception {
+            return v != null
+                    ? encoder.encodeToString(_Strings.toBytes(v.asHtml(), StandardCharsets.UTF_8))
+                    : null;
+        }
+    }
+
 }
diff --git a/api/applib/src/main/adoc/modules/applib-classes/examples/value/Password.java b/api/applib/src/main/adoc/modules/applib-classes/examples/value/Password.java
index 81ff445..45adcf7 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/examples/value/Password.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/value/Password.java
@@ -24,6 +24,7 @@ import java.util.Objects;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
 import org.apache.isis.applib.annotation.Value;
 
@@ -31,6 +32,7 @@ import org.apache.isis.applib.annotation.Value;
 // end::refguide[]
 @Value(semanticsProviderName = "org.apache.isis.core.metamodel.facets.value.password.PasswordValueSemanticsProvider")
 @XmlAccessorType(XmlAccessType.FIELD)
+// @XmlJavaTypeAdapter(Password.JaxbToStringAdapter.class) // TODO: not automatically registered because not secure enough.  Instead we should set up some sort of mechanism to encrypt.
 @lombok.Value
 public class Password implements Serializable {
     
@@ -63,8 +65,19 @@ public class Password implements Serializable {
     }
 
 
+    public static class JaxbToStringAdapter extends javax.xml.bind.annotation.adapters.XmlAdapter<String, Password> {
+        @Override
+        public Password unmarshal(String str) throws Exception {
+            return str != null
+                    ? new Password(str)
+                    : null;
+        }
 
-    
-
-    
+        @Override
+        public String marshal(Password password) throws Exception {
+            return password != null
+                    ? password.getPassword()
+                    : null;
+        }
+    }
 }
diff --git a/api/applib/src/main/adoc/modules/applib-classes/pages/roles-mixins-contributees/contributee.adoc b/api/applib/src/main/adoc/modules/applib-classes/pages/roles-mixins-contributees/contributee.adoc
index ceb933a..c636f2d 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/pages/roles-mixins-contributees/contributee.adoc
+++ b/api/applib/src/main/adoc/modules/applib-classes/pages/roles-mixins-contributees/contributee.adoc
@@ -9,20 +9,16 @@ The interfaces listed in this chapter act as contributees; they allow domain ser
 [[HasUniqueId]]
 == `HasUniqueId`
 
-The `HasUniqueId` interface is a mix-in for any domain objects that reference a transaction id, such as auditing entries or commands, or for xref:refguide:applib-svc:InteractionContext.adoc[`Interaction`]s persisted as published events.
-
-[NOTE]
-====
-This identifier actually is for the request/interaction in which the object was created, so is actually now mis-named.
-====
+The `HasUniqueId` interface is a mix-in for any domain objects that are uniquely identified, in particular to represent a system-level request or interaction.
+The canonical usage is where the unique identifier is actually a transaction id, as implemented by auditing entries or commands, or for xref:refguide:applib-svc:InteractionContext.adoc[`Interaction`]s persisted as published events.
 
 The interface is defined is:
 
 [source,java]
 ----
 public interface HasUniqueId {
-    public UUID getTransactionId();                             // <.>
-    public void setTransactionId(final UUID transactionId);
+    public UUID getUniqueId();                             // <.>
+    public void setUniqueId(final UUID uniqueId);
 }
 ----
 <.> unique identifier (a GUID) of this request/interaction.
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/DomainChangeRecord.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/DomainChangeRecord.java
new file mode 100644
index 0000000..7cfc48d
--- /dev/null
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/DomainChangeRecord.java
@@ -0,0 +1,155 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.applib.services;
+
+import java.sql.Timestamp;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.Optionality;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.annotation.PropertyLayout;
+import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
+import org.apache.isis.applib.services.message.MessageService;
+import org.apache.isis.applib.services.metamodel.BeanSort;
+import org.apache.isis.applib.services.metamodel.MetaModelService;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
+
+
+/**
+ * An abstraction of some sort of recorded change to a domain object: commands, audit entries or published events.
+ */
+public interface DomainChangeRecord extends HasUniqueId, HasUsername {
+
+    enum ChangeType {
+        COMMAND,
+        AUDIT_ENTRY,
+        PUBLISHED_INTERACTION;
+        @Override
+        public String toString() {
+            return name().replace("_", " ");
+        }
+    }
+
+    /**
+     * Distinguishes commands from audit entries from published events/interactions (when these are shown mixed together in a (standalone) table).
+     */
+    @Property
+    @PropertyLayout(hidden = Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @MemberOrder(name="Identifiers", sequence = "1")
+    ChangeType getType();
+
+
+    /**
+     * The unique identifier (a GUID) of the transaction in which this change occurred.
+     */
+    @Property
+    @MemberOrder(name="Identifiers",sequence = "50")
+    UUID getUniqueId();
+
+
+    /**
+     * The user that caused the change.
+     */
+    @Property
+    @MemberOrder(name="Identifiers", sequence = "10")
+    String getUsername();
+
+
+    /**
+     * The time that the change occurred.
+     */
+    @Property
+    @MemberOrder(name="Identifiers", sequence = "20")
+    Timestamp getTimestamp();
+
+
+    /**
+     * The object type of the domain object being changed.
+     */
+    @Property
+    @PropertyLayout(named="Object Type")
+    @MemberOrder(name="Target", sequence = "10")
+    default String getTargetObjectType() {
+        return getTarget().getObjectType();
+    }
+
+
+
+    /**
+     * The {@link Bookmark} identifying the domain object that has changed.
+     */
+    @Property
+    @PropertyLayout(named="Object")
+    @MemberOrder(name="Target", sequence="30")
+    Bookmark getTarget();
+
+
+    /**
+     * The member interaction (ie action invocation or property edit) which caused the domain object to be changed.
+     *
+     * <p>
+     *     Populated for commands and for published events that represent action invocations or property edits.
+     * </p>
+     */
+    @Property(optionality = Optionality.OPTIONAL)
+    @PropertyLayout(named="Member", hidden = Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @MemberOrder(name="Target", sequence = "20")
+    String getTargetMember();
+
+
+    /**
+     * The value of the property prior to it being changed.
+     *
+     * <p>
+     * Populated only for audit entries.
+     * </p>
+     */
+    @Property(optionality = Optionality.OPTIONAL)
+    @PropertyLayout(hidden = Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @MemberOrder(name="Detail",sequence = "6")
+    String getPreValue();
+
+
+    /**
+     * The value of the property after it has changed.
+     *
+     * <p>
+     * Populated only for audit entries.
+     * </p>
+     */
+    @Property(optionality = Optionality.MANDATORY)
+    @PropertyLayout(hidden = Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @MemberOrder(name="Detail",sequence = "7")
+    String getPostValue();
+
+
+}
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/DomainChangeRecord_openTargetObject.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/DomainChangeRecord_openTargetObject.java
new file mode 100644
index 0000000..7033bb5
--- /dev/null
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/DomainChangeRecord_openTargetObject.java
@@ -0,0 +1,61 @@
+package org.apache.isis.applib.services;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
+import org.apache.isis.applib.services.message.MessageService;
+import org.apache.isis.applib.services.metamodel.BeanSort;
+import org.apache.isis.applib.services.metamodel.MetaModelService;
+
+@Action(
+        semantics = SemanticsOf.SAFE
+        , associateWith = "target"
+        , associateWithSequence = "1"
+)
+@ActionLayout(named = "Open")
+public class DomainChangeRecord_openTargetObject {
+
+    private final DomainChangeRecord domainChangeRecord;
+    public DomainChangeRecord_openTargetObject(DomainChangeRecord domainChangeRecord) {
+        this.domainChangeRecord = domainChangeRecord;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE, associateWith = "target", associateWithSequence = "1")
+    @ActionLayout(named = "Open")
+    public Object openTargetObject() {
+        try {
+            return bookmarkService != null
+                    ? bookmarkService.lookup(domainChangeRecord.getTarget())
+                    : null;
+        } catch(RuntimeException ex) {
+            if(ex.getClass().getName().contains("ObjectNotFoundException")) {
+                messageService.warnUser("Object not found - has it since been deleted?");
+                return null;
+            }
+            throw ex;
+        }
+    }
+
+    public boolean hideOpenTargetObject() {
+        return domainChangeRecord.getTarget() == null;
+    }
+
+    public String disableOpenTargetObject() {
+        final Object targetObject = domainChangeRecord.getTarget();
+        if (targetObject == null) {
+            return null;
+        }
+        final BeanSort sortOfObject = metaModelService.sortOf(domainChangeRecord.getTarget(), MetaModelService.Mode.RELAXED);
+        return !(sortOfObject.isViewModel() || sortOfObject.isEntity())
+                ? "Can only open view models or entities"
+                : null;
+    }
+
+    @Inject BookmarkService bookmarkService;
+    @Inject MessageService messageService;
+    @Inject MetaModelService metaModelService;
+
+}
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/HasUsername.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/HasUsername.java
index 7f7a240..4860b92 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/HasUsername.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/HasUsername.java
@@ -29,6 +29,10 @@ package org.apache.isis.applib.services;
 // tag::refguide[]
 public interface HasUsername {
 
+    /**
+     * The user that created this object.
+     * @return
+     */
     String getUsername();
 
 }
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/TransactionScopeListener.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/TransactionScopeListener.java
index 4c01d24..028bf40 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/TransactionScopeListener.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/TransactionScopeListener.java
@@ -19,11 +19,14 @@
 
 package org.apache.isis.applib.services;
 
+import org.apache.isis.applib.annotation.IsisInteractionScope;
+
 /**
- * Domain services that need to be aware of transaction boundaries can implement this interface.
+ * Domain services that need to be aware of transaction boundaries can
+ * implement this interface.
  * 
- * @apiNote Implementing services most likely need to be scoped in a way that binds the scope to 
- * the current thread (eg. {@link IsisInteractionScope}) 
+ * @apiNote Implementing services most likely need to be scoped in a way that
+ * binds the scope to the current thread (eg. {@link IsisInteractionScope})
  *  
  * @since 2.0 (renamed from WithTransactionScope)
  */
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/background/BackgroundCommandService.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/background/BackgroundCommandService.java
deleted file mode 100644
index 4fcf317..0000000
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/background/BackgroundCommandService.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.applib.services.background;
-
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.schema.cmd.v2.CommandDto;
-
-/**
- * Persists a {@link org.apache.isis.schema.cmd.v1.CommandDto command-reified} action such that it can be executed asynchronously,
- * for example through a Quartz scheduler.
- *
- * <p>
- * Separate from {@link BackgroundService} primarily so that the default
- * implementation, <tt>BackgroundServiceDefault</tt> (in <tt>isis-module-background</tt>) can
- * delegate to different implementations of this service.
- *
- * <p>
- * There is currently only implementation of this service, <tt>BackgroundCommandServiceJdo</tt> in
- * <tt>o.a.i.module:isis-module-command-jdo</tt>.  That implementation has no UI and no side-effects (the programmatic
- * API is through {@link org.apache.isis.applib.services.background.BackgroundService}).  It is therefore
- * annotated with {@link org.apache.isis.applib.annotation.DomainService} so that it is automatically registered as
- * a service.
- *
- */
-// tag::refguide[]
-public interface BackgroundCommandService extends AutoCloseable {
-
-    void schedule(
-            final CommandDto dto,
-            final Command parentCommand,
-            final String targetClassName,
-            final String targetActionName,
-            final String targetArgs);
-
-    /**
-     * @apiNote refined from AutoCloseable to not throw catched exceptions
-     */
-    @Override
-    default void close() {
-    }
-
-}
-// end::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/bookmark/Bookmark.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/bookmark/Bookmark.java
index 524fc48..0c4e17b 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/bookmark/Bookmark.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/bookmark/Bookmark.java
@@ -73,6 +73,7 @@ public class Bookmark implements Serializable {
 
     /**
      * Round-trip with {@link #toString()} representation.
+     * @return
      */
     // tag::refguide[]
     public static Optional<Bookmark> parse(@Nullable String str) {
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/Command.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/Command.java
index f030cb6..5967960 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/Command.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/Command.java
@@ -19,200 +19,131 @@
 package org.apache.isis.applib.services.command;
 
 import java.sql.Timestamp;
+import java.util.UUID;
 
-import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.CommandPersistence;
 import org.apache.isis.applib.events.domain.ActionDomainEvent;
 import org.apache.isis.applib.services.HasUniqueId;
-import org.apache.isis.applib.services.background.BackgroundCommandService;
+import org.apache.isis.applib.services.HasUsername;
 import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.wrapper.WrapperFactory;
+import org.apache.isis.applib.services.wrapper.control.AsyncControl;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
+import static org.apache.isis.applib.jaxb.JavaSqlXMLGregorianCalendarMarshalling.toTimestamp;
+
+import lombok.Getter;
+
 /**
  * Represents the <i>intention to</i> invoke either an action or modify a property.  There can be only one such
- * intention per (web) request, so a command is in effect request-scoped.  Note that {@link CommandContext} domain
- * service - from which the current {@link Command} can be obtained - is indeed annotated with
- * {@link javax.enterprise.context.RequestScoped @RequestScoped}.
+ * intention per (web) request, so a command is in effect interaction-scoped.
  *
  * <p>
- * Each Command can be reified into a {@link Command#getMemento() memento} by way of the (internal)
- * <tt>CommandDtoServiceInternal</tt> domain service; typically corresponding to the XML equivalent of a
- * {@link CommandDto} and conforming to the Apache Isis <a href="http://isis.apache.org/schema/cmd/">cmd</a> schema.
+ * Each Command holds a {@link CommandDto} (see Apache Isis <a href="http://isis.apache.org/schema/cmd/">cmd</a> schema)
+ * which reifies all the details in a serializable form.
  * </p>
  *
  * <p>
- *     The {@link Command} interface also captures details of the corresponding action invocation (or property edit),
+ *     It also captures details of the corresponding action invocation (or property edit),
  *     specifically when that action/edit {@link Command#getStartedAt() started} or
  *     {@link Command#getCompletedAt() completed}, and its result, either a {@link Command#getResult() return value}
  *     or an {@link Command#getException() exception}.  Also captures a stack of {@link ActionDomainEvent}s.
  * </p>
  *
  * <p>
- *     Note that when invoking an action, other actions may be invoked courtesy of the {@link WrapperFactory}.  These
- *     "sub-actions" do <i>not</i> modify the contents of the command object; in other words think of the command
+ *     Note that when invoking an action, other actions may be invoked courtesy
+ *     of the {@link WrapperFactory}.  These "sub-actions" do <i>not</i> modify
+ *     the contents of the current command object; in other words think of the command
  *     object as representing the outer-most originating action.
  * </p>
  *
  * <p>
- *     <b>NOTE</b>: in Isis v1.x, one of the responsibilities of {@link Command} was to generate unique sequence numbers for
- *     a given transactionId, where there were three possible sequences that might be generated.
- *     <ul>
- *         <li>
- *         <p>the sequence of changed domain objects being published by the
- *         {@link org.apache.isis.applib.services.publish.PublisherService#publish(Interaction.Execution)}
- *         </p>
- *         <p>
- *         In v2 ... TODO[2158] - what replaces this?
- *         </p>
- *         </li>
- *
- *         <li>
- *         <p>
- *         The sequence of wrapped action invocations (each being published)
- *         </p>
- *         <p>
- *         In v2 this is now done by {@link Interaction#next(String) Interaction} itself.
- *         </p>
- *         </li>
- *
- *         <li>
- *         <p>
- *         and finally, one or more background commands that might be scheduled via the <code>BackgroundService</code>.
- *         </p>
- *         <p>
- *         In v2 ... TODO[2158] - what replaces this?
- *         </p>
- *         </li>
- *     </ul>
- *
+ *     That said, if the sub-action is invoked asynchronously (using
+ *     {@link WrapperFactory#asyncWrap(Object, AsyncControl)} or
+ *     {@link WrapperFactory#asyncWrapMixin(Class, Object, AsyncControl)}), then
+ *     a separate {@link Command} object
+ *     is created, and the originating {@link Command} is set to be its
+ *     {@link Command#getParent() parent}.
  * </p>
- *
  */
 // tag::refguide[]
-public interface Command extends HasUniqueId {
+public class Command implements HasUniqueId, HasUsername {
 
-    // end::refguide[]
-    /**
-     * The user that created the command.
-     */
-    // tag::refguide[]
-    String getUser();                           // <.>
-    // end::refguide[]
+    public Command() {
+        this(UUID.randomUUID());
+    }
+    public Command(final Command parent, final CommandDto commandDto) {
+        this(UUID.fromString(commandDto.getTransactionId()));
+        internal().setCommandDto(commandDto);
+        internal().setParent(parent);
+        internal().setUsername(commandDto.getUser());
+        internal().setTimestamp(toTimestamp(commandDto.getTimestamp()));
+    }
 
-    /**
-     * The date/time at which this command was created.
-     */
-    // tag::refguide[]
-    Timestamp getTimestamp();                   // <.>
-    // end::refguide[]
+    private Command(final UUID uuid) {
+        this.uniqueId = uuid;
+    }
 
-    /**
-     * {@link Bookmark} of the target object (entity or service) on which this action was performed.
-     *
-     * <p>
-     * Will only be populated if a {@link BookmarkService} has been configured.
-     * </p>
-     */
-    // tag::refguide[]
-    Bookmark getTarget();                       // <.>
-    // end::refguide[]
 
-    /**
-     * Holds a string representation of the invoked action, or the edited property, equivalent to
-     * {@link Identifier#toClassAndNameIdentityString()}.
-     */
-    // tag::refguide[]
-    String getMemberIdentifier();               // <.>
-    // end::refguide[]
+    @Getter
+    private UUID uniqueId;
 
+    // end::refguide[]
     /**
-     * A human-friendly description of the class of the target object.
+     * The user that created the command.
      */
     // tag::refguide[]
-    String getTargetClass();                    // <.>
+    @Getter
+    private String username;                    // <.>
     // end::refguide[]
 
     /**
-     * The human-friendly name of the action invoked/property edited on the target object.
+     * The date/time at which this command was created.
      */
     // tag::refguide[]
-    String getTargetAction();                   // <.>
+    @Getter
+    private Timestamp timestamp;                // <.>
     // end::refguide[]
 
     /**
-     * A human-friendly description of the arguments with which the action was invoked.
+     * Serializable representation of the action invocation/property edit.
      */
     // tag::refguide[]
-    String getArguments();                      // <.>
+    @Getter
+    private CommandDto commandDto;              // <.>
     // end::refguide[]
 
     /**
-     *
-     * A formal (XML or similar) specification of the action to invoke/being invoked.
+     * Also available in {@link #getCommandDto()}, is the {@link Bookmark} of
+     * the target object (entity or service) on which this action/edit was performed.
      */
     // tag::refguide[]
-    String getMemento();                        // <.>
+    @Getter
+    private Bookmark target;                    // <.>
     // end::refguide[]
 
     /**
-     *
-     * The mechanism by which this command is to be executed, either synchronously &quot;in the
-     * {@link CommandExecuteIn#FOREGROUND foreground}&quot; or is to be executed asynchronously &quot;in the
-     * {@link CommandExecuteIn#BACKGROUND background}&quot; through the {@link BackgroundCommandService}.
+     * Also available in {@link #getCommandDto()}, holds a string
+     * representation of the invoked action, or the edited property.
      */
     // tag::refguide[]
-    CommandExecuteIn getExecuteIn();            // <.>
+    @Getter
+    private String logicalMemberIdentifier;     // <.>
     // end::refguide[]
 
-    // tag::refguide2[]
-    enum Executor {
-        // end::refguide2[]
-        /**
-         * Command being executed by the end-user.
-         */
-        // tag::refguide2[]
-        USER,
-        // end::refguide2[]
-        /**
-         * Command being executed by a background execution service.
-         */
-        // tag::refguide2[]
-        BACKGROUND,
-        // end::refguide2[]
-        /**
-         * Command being executed for some other reason, eg as result of redirect-after-post, or the homePage action.
-         */
-        // tag::refguide2[]
-        OTHER
-    }
-    // end::refguide2[]
-
     /**
-     * The (current) executor of this command.
-     *
-     * <p>
-     * Note that (even for implementations of {@link BackgroundCommandService} that persist {@link Command}s), this
-     * property is never (likely to be) persisted, because it is always updated to indicate how the command is
-     * currently being executed.
+     * For commands created through the {@link WrapperFactory} (using
+     * {@link WrapperFactory#asyncWrap(Object, AsyncControl)} or
+     * {@link WrapperFactory#asyncWrapMixin(Class, Object, AsyncControl)}),
+     * captures the parent command.
      *
      * <p>
-     * If the {@link #getExecutor() executor} matches the required {@link #getExecuteIn() execution policy}, then the
-     * command actually is executed.  The combinations are:
-     * <ul>
-     * <li>executor = USER, executeIn = FOREGROUND, then execute</li>
-     * <li>executor = USER, executeIn = BACKGROUND, then persist and return persisted command as a placeholder for the result</li>
-     * <li>executor = BACKGROUND, executeIn = FOREGROUND, then ignore</li>
-     * <li>executor = BACKGROUND, executeIn = BACKGROUND, then execute, update the command with result</li>
-     * </ul>
-     *
+     *     Will return <code>null</code> if there is no parent.
+     * </p>
      */
     // tag::refguide[]
-    Executor getExecutor();                     // <.>
+    @Getter
+    private Command parent;                     // <.>
     // end::refguide[]
 
     /**
@@ -229,7 +160,8 @@ public interface Command extends HasUniqueId {
      * {@link Interaction.Execution#getStartedAt()}.
      */
     // tag::refguide[]
-    Timestamp getStartedAt();                   // <.>
+    @Getter
+    private Timestamp startedAt;                // <.>
     // end::refguide[]
 
     /**
@@ -246,224 +178,170 @@ public interface Command extends HasUniqueId {
      * {@link Interaction.Execution#getCompletedAt()}.
      */
     // tag::refguide[]
-    Timestamp getCompletedAt();                 // <.>
-    // end::refguide[]
-
-    /**
-     * For actions created through the {@link BackgroundService} and {@link BackgroundCommandService},
-     * captures the parent action.
-     */
-    // tag::refguide[]
-    Command getParent();                        // <.>
+    @Getter
+    private Timestamp completedAt;              // <.>
     // end::refguide[]
 
     /**
-     * For an command that has actually been executed, holds the exception stack
-     * trace if the action invocation/property modification threw an exception.
+     * For a command that has actually been executed, holds a {@link Bookmark}
+     * to the object returned by the corresponding action/property modification.
      *
      * <p>
-     *     Previously this field was deprecated (on the basis that the exception is also held in
-     *     {@link Interaction.Execution#getThrew()}). However, this property is now used in master/slave
-     *     replay scenarios which may query a persisted Command.
+     *     This property is used in replay scenarios to verify the outcome of
+     *     the replayed command, eg for regression testing.
      * </p>
      *
-     * See also {@link Interaction#getCurrentExecution()} and  {@link org.apache.isis.applib.services.iactn.Interaction.Execution#getThrew()}.
+     * See also  {@link Interaction#getCurrentExecution()} and
+     * {@link org.apache.isis.applib.services.iactn.Interaction.Execution#getReturned()}.
      */
     // tag::refguide[]
-    String getException();                      // <.>
+    @Getter
+    private Bookmark result;                    // <.>
     // end::refguide[]
 
     /**
-     * For an command that has actually been executed, holds a {@link Bookmark} to the object returned by the corresponding action/property modification.
+     * For a command that has actually been executed, holds the exception stack
+     * trace if the action invocation/property modification threw an exception.
      *
      * <p>
-     *     Previously this field was deprecated (on the basis that the returned value is also held in
-     *     {@link Interaction.Execution#getReturned()}). However, this property is now used in master/slave
-     *     replay scenarios which may query a persisted Command.
+     *     This property is used in replay scenarios to verify the outcome of
+     *     the replayed command, eg for regression testing.
      * </p>
      *
-     * See also  {@link Interaction#getCurrentExecution()} and  {@link org.apache.isis.applib.services.iactn.Interaction.Execution#getReturned()}.
+     * See also {@link Interaction#getCurrentExecution()} and
+     * {@link org.apache.isis.applib.services.iactn.Interaction.Execution#getThrew()}.
      */
     // tag::refguide[]
-    Bookmark getResult();                       // <.>
+    @Getter
+    private Throwable exception;                    // <.>
     // end::refguide[]
 
     /**
-     * Whether this command should ultimately be persisted (if the configured {@link BackgroundCommandService} supports
-     * it) or not.
+     * Whether this command resulted in a change of state to the system.
      *
      * <p>
-     * If the action to be executed has been annotated with the {@link Action#command()} attribute
-     * then (unless its {@link Action#commandPersistence()} persistence} attribute has been set to a different value
-     * than its default of {@link org.apache.isis.applib.annotation.CommandPersistence#PERSISTED persisted}), the
-     * {@link Command} object will be persisted.
-     *
-     * <p>
-     * However, it is possible to prevent the {@link Command} object from ever being persisted by setting the
-     * {@link org.apache.isis.applib.annotation.Action#commandPersistence() persistence} attribute to
-     * {@link org.apache.isis.applib.annotation.CommandPersistence#NOT_PERSISTED}, or it can be set to
-     * {@link org.apache.isis.applib.annotation.CommandPersistence#IF_HINTED}, meaning it is dependent
-     * on whether {@link #setPersistHint(boolean) a hint has been set} by some other means.
+     *     This can be used as a hint to decide whether to persist the command
+     *     to a datastore, for example for auditing (though
+     *     {@link org.apache.isis.applib.services.publish.PublisherService} is
+     *     an alternative for that use case) or so that it can be retrieved
+     *     and replayed on another system, eg for regression testing.
+     * </p>
      *
-     * <p>
-     * For example, a {@link BackgroundCommandService} implementation that creates persisted background commands ought
-     * associate them (via its {@link Command#getParent() parent}) to an original persisted
-     * {@link Command}.  The hinting mechanism allows the service to suggest that the parent command be persisted so
-     * that the app can then provide a mechanism to find all child background commands for that original parent command.
      */
     // tag::refguide[]
-    CommandPersistence getPersistence();        // <.>
+    @Getter
+    private boolean systemStateChanged;                // <.>
     // end::refguide[]
 
-    /**
-     * Whether that this {@link Command} should be persisted, if possible.
-     */
-    // tag::refguide[]
-    boolean isPersistHint();                    // <.>
-    // end::refguide[]
 
-    /**
-     * <b>NOT API</b>: intended to be called only by the framework.
-     */
-    public static interface Internal {
+    private final Command.Internal INTERNAL = new Internal();
 
+    public class Internal {
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
          * Implementation notes: set when the Isis PersistenceSession is opened.
          */
-        void setUser(String user);
-
+        public void setUsername(String username) {
+            Command.this.username = username;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
          * Implementation notes: set when the Isis PersistenceSession is opened.
          */
-        void setTimestamp(Timestamp timestamp);
-
+        public void setTimestamp(Timestamp timestamp) {
+            Command.this.timestamp = timestamp;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
-         * Implementation notes: set when the action is invoked (in the ActionInvocationFacet).
+         *     Only populated for async commands created through the
+         *     {@link WrapperFactory}.
+         * </p>
          */
-        void setTarget(Bookmark target);
-
+        public void setParent(Command parent) {
+            Command.this.parent = parent;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
-         * Implementation notes: set when the action is invoked (in <tt>ActionInvocationFacet</tt>) or in
-         * property edited (in <tt>PropertySetterFacet</tt>).
+         * Implementation notes: set when the action is invoked (in the <tt>ActionInvocationFacet</tt>).
+         * @param commandDto
          */
-        void setMemberIdentifier(String memberIdentifier);
-
+        public void setCommandDto(CommandDto commandDto) {
+            Command.this.commandDto = commandDto;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
-         * Implementation notes: set when the action is invoked (in the <tt>ActionInvocationFacet</tt>) or property edited
-         * (in the <tt>PropertySetterOrClearFacet</tt>).
+         * Implementation notes: set when the action is invoked (in the ActionInvocationFacet).
          */
-        void setTargetAction(String targetAction);
-
-
+        public void setTarget(Bookmark target) {
+            Command.this.target = target;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
-         * Implementation notes: set when the action is invoked (in the <tt>ActionInvocationFacet</tt>).
+         * Implementation notes: set when the action is invoked (in
+         * <tt>ActionInvocationFacet</tt>) or property is edited (in
+         * <tt>PropertySetterFacet</tt>).
          */
-        void setArguments(final String arguments);
-
+        public void setLogicalMemberIdentifier(String logicalMemberIdentifier) {
+            Command.this.logicalMemberIdentifier = logicalMemberIdentifier;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          */
-        void setExecutor(final Executor executor);
-
+        public void setStartedAt(Timestamp startedAt) {
+            Command.this.startedAt = startedAt;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          */
-        void setResult(Bookmark resultBookmark);
-
+        public void setCompletedAt(final Timestamp completed) {
+            Command.this.completedAt = completed;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          */
-        void setException(String stackTrace);
-
+        public void setResult(final Bookmark result) {
+            Command.this.result = result;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          */
-        void setParent(final Command parent);
-
+        public void setException(final Throwable exception) {
+            Command.this.exception = exception;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
-         *     Previously this field was deprecated (on the basis that the completedAt is also held in
-         *     {@link Interaction.Execution#getCompletedAt()}). However, this property is now used in master/slave
-         *     replay scenarios which may query a persisted Command.
+         * Hint that this {@link Command} has resulted in a change of state to the system.
+         * Implementations can use this to persist the command, for example.
          * </p>
-         *
-         * See also {@link Interaction#getCurrentExecution()} and
-         * {@link Interaction.Execution#setCompletedAt(Timestamp)}.
          */
-        void setCompletedAt(Timestamp completedAt);
-
-        /**
-         * <b>NOT API</b>: intended to be called only by the framework.
-         *
-         *
-         * <p>
-         *     Previously this field was deprecated (on the basis that the completedAt is also held in
-         *     {@link Interaction.Execution#getCompletedAt()}). However, this property is now used in master/slave
-         *     replay scenarios which may query a persisted Command.
-         * </p>
-         *
-         * See also {@link Interaction#getCurrentExecution()} and
-         * {@link #setStartedAt(org.apache.isis.applib.services.clock.ClockService, org.apache.isis.applib.services.metrics.MetricsService)}.
-         */
-        void setStartedAt(Timestamp startedAt);
-
-        /**
-         * <b>NOT API</b>: intended to be called only by the framework.
-         *
-         * <p>
-         * Implementation notes: set when the action is invoked (in the <tt>ActionInvocationFacet</tt>).
-         */
-        void setMemento(final String memento);
-
-        /**
-         * <b>NOT API</b>: intended to be called only by the framework.
-         *
-         * <p>
-         * Implementation notes: set when the action is invoked (in the <tt>ActionInvocationFacet</t>).
-         */
-        void setTargetClass(String targetClass);
-
-        /**
-         * <b>NOT API</b>: intended to be called only by the framework.
-         */
-        void setPersistence(final CommandPersistence persistence);
-
-        /**
-         * Hint that this {@link Command} should be persisted, if possible.
-         *
-         * <p>
-         * <b>NOT API</b>: intended to be called only by the framework.
-         *
-         * @see #getPersistence()
-         */
-        void setPersistHint(boolean persistHint);
-    }
+        public void setSystemStateChanged(boolean systemStateChanged) {
+            Command.this.systemStateChanged = systemStateChanged;
+        }
+    };
 
     /**
      * <b>NOT API</b>: intended to be called only by the framework.
      */
-    Internal internal();
+    public Command.Internal internal() {
+        return INTERNAL;
+    }
+
 
 // tag::refguide[]
+
 }
 // end::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandContext.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandContext.java
index cf71f1b..dea7b9a 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandContext.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandContext.java
@@ -20,10 +20,10 @@ package org.apache.isis.applib.services.command;
 
 import java.util.Optional;
 
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
+import javax.inject.Inject;
 import javax.inject.Named;
 
+import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Primary;
 import org.springframework.core.annotation.Order;
@@ -31,10 +31,13 @@ import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.IsisInteractionScope;
 import org.apache.isis.applib.annotation.OrderPrecedence;
-import org.apache.isis.applib.services.command.Command.Executor;
+import org.apache.isis.applib.services.TransactionScopeListener;
+import org.apache.isis.applib.services.inject.ServiceInjector;
+import org.apache.isis.applib.services.metrics.MetricsService;
+import org.apache.isis.applib.services.registry.ServiceRegistry;
 
 import lombok.Getter;
-import lombok.extern.log4j.Log4j2;
+import lombok.RequiredArgsConstructor;
 
 /**
  * This service (API and implementation) provides access to context information about any {@link Command}.
@@ -46,12 +49,16 @@ import lombok.extern.log4j.Log4j2;
 // tag::refguide[]
 @Service
 @Named("isisApplib.CommandContext")
-@Order(OrderPrecedence.MIDPOINT)
+@Order(OrderPrecedence.EARLY - 10) // before ChangedObjectService
 @Primary
 @Qualifier("Default")
 @IsisInteractionScope
-@Log4j2
-public class CommandContext {
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
+//@Log4j2
+public class CommandContext implements TransactionScopeListener, DisposableBean {
+
+    private final ServiceInjector serviceInjector;
+    private final MetricsService metricsService;
 
     @Getter
     private Command command;
@@ -62,11 +69,21 @@ public class CommandContext {
      */
     public void setCommand(final Command command) {
         this.command = command;
+        if(command!=null) {
+            serviceInjector.injectServicesInto(command);
+        }
+    }
+
+    @Override
+    public void destroy() throws Exception {
+        setCommand(null);
     }
 
-    public Optional<Executor> getCurrentExecutor() {
-        return Optional.ofNullable(getCommand())
-                .map(Command::getExecutor);
+    @Override
+    public void onTransactionEnded() {
+        getCommand().internal().setSystemStateChanged(
+                getCommand().isSystemStateChanged() ||
+                metricsService.numberObjectsDirtied() > 0);
     }
 
     // tag::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDefault.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDefault.java
deleted file mode 100644
index 069acd4..0000000
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDefault.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.applib.services.command;
-
-import java.sql.Timestamp;
-import java.util.UUID;
-
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.CommandPersistence;
-import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.applib.util.ObjectContracts;
-import org.apache.isis.applib.util.ToString;
-
-import lombok.Getter;
-
-public class CommandDefault implements Command {
-
-    public CommandDefault() {
-        this.executor = Executor.OTHER;
-        this.uniqueId = UUID.randomUUID();
-    }
-
-    @Getter
-    private String memberIdentifier;
-
-    @Getter
-    private String targetClass;
-
-    @Getter
-    private String targetAction;
-
-    @Getter
-    private String arguments;
-
-    @Getter
-    private String memento;
-
-    @Getter
-    private Bookmark target;
-
-    @Getter
-    private Timestamp timestamp;
-
-    @Getter
-    private Timestamp startedAt;
-
-    @Getter
-    private Timestamp completedAt;
-
-    @Getter
-    private String user;
-
-    @Getter
-    private Executor executor;
-
-    @Getter
-    private CommandExecuteIn executeIn;
-
-    @Getter
-    private Command parent;
-
-    @Getter
-    private Bookmark result;
-
-    @Getter
-    private String exception;
-
-    @Getter
-    private UUID uniqueId;
-
-    @Getter
-    private CommandPersistence persistence;
-
-    @Getter
-    private boolean persistHint;
-
-    // -- toString
-
-    private static final ToString<CommandDefault> toString = ObjectContracts
-            .toString("startedAt", CommandDefault::getStartedAt)
-            .thenToString("user", CommandDefault::getUser)
-            .thenToString("memberIdentifier", CommandDefault::getMemberIdentifier)
-            .thenToString("target", CommandDefault::getTarget)
-            .thenToString("transactionId", CommandDefault::getUniqueId);
-
-    @Override
-    public String toString() {
-        return toString.toString(this);
-    }
-
-
-    // -- FRAMEWORK INTERNAL
-
-    private final Command.Internal INTERNAL = new Command.Internal() {
-        @Override
-        public void setMemberIdentifier(String actionIdentifier) {
-            CommandDefault.this.memberIdentifier = actionIdentifier;
-        }
-        @Override
-        public void setTargetClass(String targetClass) {
-            CommandDefault.this.targetClass = targetClass;
-        }
-        @Override
-        public void setTargetAction(String targetAction) {
-            CommandDefault.this.targetAction = targetAction;
-        }
-        @Override
-        public void setArguments(String arguments) {
-            CommandDefault.this.arguments = arguments;
-        }
-        @Override
-        public void setMemento(String memento) {
-            CommandDefault.this.memento = memento;
-        }
-        @Override
-        public void setTarget(Bookmark target) {
-            CommandDefault.this.target = target;
-        }
-        @Override
-        public void setTimestamp(Timestamp timestamp) {
-            CommandDefault.this.timestamp = timestamp;
-        }
-        @Override
-        public void setStartedAt(Timestamp startedAt) {
-            CommandDefault.this.startedAt = startedAt;
-        }
-        @Override
-        public void setCompletedAt(final Timestamp completed) {
-            CommandDefault.this.completedAt = completed;
-        }
-        @Override
-        public void setUser(String user) {
-            CommandDefault.this.user = user;
-        }
-        @Override
-        public void setParent(Command parent) {
-            CommandDefault.this.parent = parent;
-        }
-        @Override
-        public void setResult(final Bookmark result) {
-            CommandDefault.this.result = result;
-        }
-        @Override
-        public void setException(final String exceptionStackTrace) {
-            CommandDefault.this.exception = exceptionStackTrace;
-        }
-        @Override
-        public void setPersistence(CommandPersistence persistence) {
-            CommandDefault.this.persistence = persistence;
-        }
-        @Override
-        public void setPersistHint(boolean persistHint) {
-            CommandDefault.this.persistHint = persistHint;
-        }
-        @Override
-        public void setExecutor(Executor executor) {
-            CommandDefault.this.executor = executor;
-        }
-    };
-
-    @Override
-    public Command.Internal internal() {
-        return INTERNAL;
-    }
-
-}
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDtoProcessor.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDtoProcessor.java
index 3c7336e..60edc81 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDtoProcessor.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDtoProcessor.java
@@ -18,7 +18,6 @@
  */
 package org.apache.isis.applib.services.command;
 
-import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
 // tag::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDtoProcessorForActionAbstract.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDtoProcessorForActionAbstract.java
index 531c945..97c9780 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDtoProcessorForActionAbstract.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDtoProcessorForActionAbstract.java
@@ -27,8 +27,8 @@ import org.apache.isis.schema.cmd.v2.ParamsDto;
  * Convenience adapter for command processors for action invocations.
  */
 public abstract class CommandDtoProcessorForActionAbstract implements CommandDtoProcessor {
-    protected CommandDto asDto(final CommandWithDto commandWithDto) {
-        return commandWithDto.asDto();
+    protected CommandDto asDto(final Command command) {
+        return command.getCommandDto();
     }
     protected ActionDto getActionDto(final CommandDto commandDto) {
         return (ActionDto) commandDto.getMember();
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDtoProcessorForPropertyAbstract.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDtoProcessorForPropertyAbstract.java
index 6bc4d69..b8e2dd3 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDtoProcessorForPropertyAbstract.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDtoProcessorForPropertyAbstract.java
@@ -26,8 +26,8 @@ import org.apache.isis.schema.cmd.v2.PropertyDto;
  */
 public abstract class CommandDtoProcessorForPropertyAbstract
 implements CommandDtoProcessor {
-    protected CommandDto asDto(final CommandWithDto commandWithDto) {
-        return commandWithDto.asDto();
+    protected CommandDto asDto(final Command commandWithDto) {
+        return commandWithDto.getCommandDto();
     }
     protected PropertyDto getPropertyDto(final CommandDto commandDto) {
         return (PropertyDto) commandDto.getMember();
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandExecutorService.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandExecutorService.java
index 56d029b..4634dc5 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandExecutorService.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandExecutorService.java
@@ -48,13 +48,22 @@ public interface CommandExecutorService {
      * Executes the specified command.
      *
      * @param sudoPolicy
-     * @param commandWithDto
+     * @param command
      * @return - any exception raised by the command.
      */
     // tag::refguide[]
-    void executeCommand(
+    Bookmark executeCommand(
+            SudoPolicy sudoPolicy,          // <.>
+            Command command                 // <.>
+    );
+
+    Bookmark executeCommand(
             SudoPolicy sudoPolicy,          // <.>
-            CommandWithDto commandWithDto   // <.>
+            CommandDto commandDto           // <.>
+    );
+
+    Bookmark executeCommand(
+            Command command                 // <.>
     );
 
     Bookmark executeCommand(
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandService.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandService.java
new file mode 100644
index 0000000..ce19893
--- /dev/null
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandService.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.applib.services.command;
+
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Primary;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Service;
+
+import org.apache.isis.applib.annotation.IsisInteractionScope;
+import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.command.spi.CommandServiceListener;
+
+import lombok.extern.log4j.Log4j2;
+
+@Service
+@Named("isisApplib.CommandService")
+@Order(OrderPrecedence.MIDPOINT)
+@Primary
+@Qualifier("Default")
+@Log4j2
+// tag::refguide[]
+public class CommandService {
+
+    // end::refguide[]
+    /**
+     * Simply instantiates the appropriate instance of the {@link Command}.
+     *
+     * <p>
+     * Its members will be populated automatically by the framework (the
+     * {@link Command}'s {@link Command#getTimestamp()},
+     * {@link Command#getUsername()} and {@link Command#getUniqueId()}).
+     * </p>
+     */
+    // tag::refguide[]
+    public Command create() {                   // <.>
+        return new Command();
+    }
+
+    // end::refguide[]
+
+    /**
+     * &quot;Complete&quot; the command, providing an opportunity ot persist
+     * a memento of the command if the
+     * {@link Command#isSystemStateChanged() system state has changed}.
+     *
+     * <p>
+     *     The framework will automatically have set the {@link Command#getCompletedAt()} property.
+     * </p>
+     */
+    // tag::refguide[]
+    public void complete(final Command command) {   // <.>
+        // ...
+    // end::refguide[]
+
+        if(command.getLogicalMemberIdentifier() == null) {
+            // eg if seed fixtures
+            return;
+        }
+
+        log.debug("complete: {}, systemStateChanged {}", command.getLogicalMemberIdentifier(), command.isSystemStateChanged());
+
+    // tag::refguide[]
+        commandServiceListeners.forEach(x -> x.onComplete(command));
+    }
+
+    @Inject List<CommandServiceListener> commandServiceListeners;
+
+}
+// end::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/spi/CommandService.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/spi/CommandService.java
deleted file mode 100644
index eb3abce..0000000
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/spi/CommandService.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.applib.services.command.spi;
-
-import org.apache.isis.applib.services.command.Command;
-
-/**
- * Default factory service for {@link Command}s.
- */
-// tag::refguide[]
-public interface CommandService {
-
-    // end::refguide[]
-    /**
-     * Simply instantiates the appropriate instance of the {@link Command}.
-     *
-     * <p>
-     * Its members will be populated automatically by the framework (the {@link Command}'s
-     * {@link Command#getTimestamp()}, {@link Command#getUser()} and {@link Command#getUniqueId()}).
-     * </p>
-     */
-    // tag::refguide[]
-    Command create();                               // <.>
-    // end::refguide[]
-
-    /**
-     * Hint for this implementation to eagerly persist the {@link Command}s if possible; influences the behaviour
-     * of actions annotated to execute in the {@link org.apache.isis.applib.annotation.CommandExecuteIn#BACKGROUND}.
-     */
-    // tag::refguide[]
-    boolean persistIfPossible(Command command);     // <.>
-    // end::refguide[]
-
-    /**
-     * &quot;Complete&quot; the command, typically meaning to indicate that the command is completed, and to
-     * persist it if its {@link Command#getPersistence()} and {@link Command#isPersistHint() persistence hint}
-     * indicate that it should be.
-     *
-     * <p>
-     * However, not every implementation necessarily {@link #persistIfPossible(Command) supports persistence}.
-     *
-     * <p>
-     *     The framework will automatically have set the {@link Command#getCompletedAt()} property.
-     * </p>
-     */
-    // tag::refguide[]
-    void complete(final Command command);           // <.>
-}
-// end::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandWithDto.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/spi/CommandServiceListener.java
similarity index 63%
rename from api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandWithDto.java
rename to api/applib/src/main/adoc/modules/applib-svc/examples/services/command/spi/CommandServiceListener.java
index cd421ea..5d10793 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandWithDto.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/spi/CommandServiceListener.java
@@ -16,20 +16,25 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.applib.services.command;
+package org.apache.isis.applib.services.command.spi;
 
-import org.apache.isis.applib.annotation.Programmatic;
-import org.apache.isis.schema.cmd.v2.CommandDto;
+import org.apache.isis.applib.services.command.Command;
 
+/**
+ * SPI
+ */
 // tag::refguide[]
-public interface CommandWithDto extends Command {
-
-    String USERDATA_KEY_TARGET_CLASS = "targetClass";
-    String USERDATA_KEY_TARGET_ACTION = "targetAction";
-    String USERDATA_KEY_ARGUMENTS = "arguments";
-    String USERDATA_KEY_RETURN_VALUE = "returnValue";
-    String USERDATA_KEY_EXCEPTION = "exception";
+public interface CommandServiceListener {
 
-    CommandDto asDto();
+    /**
+     * Notifies that the command has completed.
+     *
+     * <p>
+     *     This is an opportunity for implementations to process the command,
+     *     for example to persist a representation of it.
+     * </p>
+     */
+    // tag::refguide[]
+    void onComplete(final Command command);           // <.>
 }
 // end::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/conmap/command/ContentMappingServiceForCommandDto.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/conmap/command/ContentMappingServiceForCommandDto.java
index a4cea23..c4579c4 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/conmap/command/ContentMappingServiceForCommandDto.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/conmap/command/ContentMappingServiceForCommandDto.java
@@ -20,6 +20,7 @@ package org.apache.isis.applib.services.conmap.command;
 
 import java.sql.Timestamp;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -31,14 +32,15 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.jaxb.JavaSqlXMLGregorianCalendarMarshalling;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandDtoProcessor;
-import org.apache.isis.applib.services.command.CommandWithDto;
 import org.apache.isis.applib.services.conmap.ContentMappingService;
 import org.apache.isis.applib.services.conmap.command.spi.CommandDtoProcessorService;
 import org.apache.isis.applib.services.metamodel.MetaModelService;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
+import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.common.v2.PeriodDto;
 
@@ -62,27 +64,27 @@ public class ContentMappingServiceForCommandDto implements ContentMappingService
     /**
      * Not part of the {@link ContentMappingService} API.
      */
-    public CommandDto map(final CommandWithDto commandWithDto) {
-        return asProcessedDto(commandWithDto);
+    public CommandDto map(final Command command) {
+        return asProcessedDto(command);
     }
 
     CommandDto asProcessedDto(final Object object) {
-        if (!(object instanceof CommandWithDto)) {
+        if (!(object instanceof Command)) {
             return null;
         }
-        final CommandWithDto commandWithDto = (CommandWithDto) object;
-        return asProcessedDto(commandWithDto);
+        final Command command = (Command) object;
+        return asProcessedDto(command);
     }
 
-    private CommandDto asProcessedDto(final CommandWithDto commandWithDto) {
-        if(commandWithDto == null) {
+    private CommandDto asProcessedDto(final Command command) {
+        if(command == null) {
             return null;
         }
-        CommandDto commandDto = commandWithDto.asDto();
+        CommandDto commandDto = command.getCommandDto();
 
         // global processors
         for (final CommandDtoProcessorService commandDtoProcessorService : commandDtoProcessorServices) {
-            commandDto = commandDtoProcessorService.process(commandWithDto, commandDto);
+            commandDto = commandDtoProcessorService.process(command, commandDto);
             if(commandDto == null) {
                 // any processor could return null, effectively breaking the chain.
                 return null;
@@ -95,7 +97,7 @@ public class ContentMappingServiceForCommandDto implements ContentMappingService
         if (commandDtoProcessor == null) {
             return commandDto;
         }
-        return commandDtoProcessor.process(commandWithDto, commandDto);
+        return commandDtoProcessor.process(command, commandDto);
     }
 
 
@@ -114,33 +116,28 @@ public class ContentMappingServiceForCommandDto implements ContentMappingService
         public CommandDto process(final Command command, CommandDto commandDto) {
 
             // for some reason this isn't being persisted initially, so patch it in.  TODO: should fix this
-            commandDto.setUser(command.getUser());
+            commandDto.setUser(command.getUsername());
 
             // the timestamp field was only introduced in v1.4 of cmd.xsd, so there's no guarantee
             // it will have been populated.  We therefore copy the value in from CommandWithDto entity.
             if(commandDto.getTimestamp() == null) {
                 final Timestamp timestamp = command.getTimestamp();
-                commandDto.setTimestamp(JavaSqlTimestampXmlGregorianCalendarAdapter.print(timestamp));
+                commandDto.setTimestamp(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(timestamp));
             }
 
-            CommandDtoUtils.setUserData(commandDto,
-                    CommandWithDto.USERDATA_KEY_TARGET_CLASS, command.getTargetClass());
-            CommandDtoUtils.setUserData(commandDto,
-                    CommandWithDto.USERDATA_KEY_TARGET_ACTION, command.getTargetAction());
-            CommandDtoUtils.setUserData(commandDto,
-                    CommandWithDto.USERDATA_KEY_ARGUMENTS, command.getArguments());
-
             final Bookmark result = command.getResult();
             CommandDtoUtils.setUserData(commandDto,
-                    CommandWithDto.USERDATA_KEY_RETURN_VALUE, result != null ? result.toString() : null);
+                    UserDataKeys.RESULT, result != null ? result.toString() : null);
             // knowing whether there was an exception is on the master is used to determine whether to
             // continue when replayed on the slave if an exception occurs there also
+            Throwable exception = command.getException();
             CommandDtoUtils.setUserData(commandDto,
-                    CommandWithDto.USERDATA_KEY_EXCEPTION, command.getException());
+                    UserDataKeys.EXCEPTION,
+                        _Exceptions.asStacktrace(exception));
 
             PeriodDto timings = CommandDtoUtils.timingsFor(commandDto);
-            timings.setStartedAt(JavaSqlTimestampXmlGregorianCalendarAdapter.print(command.getStartedAt()));
-            timings.setCompletedAt(JavaSqlTimestampXmlGregorianCalendarAdapter.print(command.getCompletedAt()));
+            timings.setStartedAt(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(command.getStartedAt()));
+            timings.setCompletedAt(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(command.getCompletedAt()));
 
             return commandDto;
         }
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/background/package-info.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/conmap/command/UserDataKeys.java
similarity index 65%
rename from api/applib/src/main/java/org/apache/isis/applib/services/background/package-info.java
rename to api/applib/src/main/adoc/modules/applib-svc/examples/services/conmap/command/UserDataKeys.java
index f63812d..bc1bb2f 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/background/package-info.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/conmap/command/UserDataKeys.java
@@ -16,12 +16,19 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
+package org.apache.isis.applib.services.conmap.command;
+
+import org.apache.isis.schema.cmd.v2.CommandDto;
+
+import lombok.experimental.UtilityClass;
 
 /**
- * The {@link org.apache.isis.applib.services.background.BackgroundService2} domain service, and also the companion
- * {@link org.apache.isis.applib.services.background.BackgroundCommandService2} SPI service, enable commands to be
- * persisted such that they may be invoked in the background
- *
- *
+ * Keys used in {@link CommandDto#getUserData()} to marshall the command's results
  */
-package org.apache.isis.applib.services.background;
\ No newline at end of file
+@UtilityClass
+public class UserDataKeys {
+
+    public static String RESULT = UserDataKeys.class.getName() + "#" + "RESULT";
+    public static String EXCEPTION = UserDataKeys.class.getName() + "#" + "EXCEPTION";
+
+}
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/exceprecog/ExceptionRecognizer.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/exceprecog/ExceptionRecognizer.java
index ca322a6..f51628f 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/exceprecog/ExceptionRecognizer.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/exceprecog/ExceptionRecognizer.java
@@ -158,20 +158,33 @@ public interface ExceptionRecognizer {
         public String toMessage(@Nullable TranslationService translationService) {
             // end::refguide-2[]
 
-            val categoryLiteral = translationService!=null
-                    ? translationService.translate(
-                    ExceptionRecognizer.Category.class.getName(), getCategory().getFriendlyName())
-                    : getCategory().getFriendlyName();
-
-            val reasonLiteral = translationService!=null
-                    ? translationService.translate(
-                    ExceptionRecognizer.Recognition.class.getName(), getReason())
-                    : getReason();
+            val categoryLiteral = translate(getCategory().getFriendlyName(), translationService);
+            val reasonLiteral = translate(getReason(), translationService);
 
             return String.format("[%s]: %s", categoryLiteral, reasonLiteral);
             // tag::refguide-2[]
             // ...
         }
+        
+        public String toMessageNoCategory(@Nullable TranslationService translationService) {
+            // end::refguide-2[]
+
+            val reasonLiteral = translate(getReason(), translationService);
+            return String.format("%s", reasonLiteral);
+            // tag::refguide-2[]
+            // ...
+        }
+        
+        private static String translate(
+                @Nullable String x, 
+                @Nullable TranslationService translationService) {
+            if(x==null || translationService==null) {
+                return x;
+            }
+            return translationService.translate(
+                    ExceptionRecognizer.Recognition.class.getName(), x);
+        }
+        
     }
     // end::refguide-2[]
 
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/iactn/Interaction.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/iactn/Interaction.java
index 43450df..5cfb218 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/iactn/Interaction.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/iactn/Interaction.java
@@ -30,6 +30,7 @@ import java.util.concurrent.atomic.LongAdder;
 import org.apache.isis.applib.events.domain.AbstractDomainEvent;
 import org.apache.isis.applib.events.domain.ActionDomainEvent;
 import org.apache.isis.applib.events.domain.PropertyDomainEvent;
+import org.apache.isis.applib.jaxb.JavaSqlXMLGregorianCalendarMarshalling;
 import org.apache.isis.applib.services.HasUniqueId;
 import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.command.Command;
@@ -578,7 +579,7 @@ public class Interaction implements HasUniqueId {
                     final MetricsDto metricsDto = metricsFor(execution);
 
                     final PeriodDto periodDto = timingsFor(metricsDto);
-                    periodDto.setStartedAt(JavaSqlTimestampXmlGregorianCalendarAdapter.print(timestamp));
+                    periodDto.setStartedAt(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(timestamp));
 
                     final ObjectCountsDto objectCountsDto = objectCountsFor(metricsDto);
                     numberObjectsLoadedFor(objectCountsDto).setBefore(numberObjectsLoaded);
@@ -602,7 +603,7 @@ public class Interaction implements HasUniqueId {
                     final MetricsDto metricsDto = metricsFor(execution);
 
                     final PeriodDto periodDto = timingsFor(metricsDto);
-                    periodDto.setCompletedAt(JavaSqlTimestampXmlGregorianCalendarAdapter.print(timestamp));
+                    periodDto.setCompletedAt(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(timestamp));
 
                     final ObjectCountsDto objectCountsDto = objectCountsFor(metricsDto);
                     numberObjectsLoadedFor(objectCountsDto).setAfter(numberObjectsLoaded);
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/iactn/InteractionContext.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/iactn/InteractionContext.java
index b4a94b4..86cb93c 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/iactn/InteractionContext.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/iactn/InteractionContext.java
@@ -18,8 +18,6 @@
  */
 package org.apache.isis.applib.services.iactn;
 
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
 import javax.inject.Named;
 
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -32,7 +30,6 @@ import org.apache.isis.applib.annotation.IsisInteractionScope;
 import org.apache.isis.applib.annotation.OrderPrecedence;
 
 import lombok.Getter;
-import lombok.extern.log4j.Log4j2;
 
 /**
  * This service (API and implementation) provides access to context information about any {@link Interaction}.
@@ -48,7 +45,7 @@ import lombok.extern.log4j.Log4j2;
 @Primary
 @Qualifier("Default")
 @IsisInteractionScope
-@Log4j2
+//@Log4j2
 public class InteractionContext {
 
     // end::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/jaxb/JaxbService.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/jaxb/JaxbService.java
index 47af07a..e33a1ca 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/jaxb/JaxbService.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/jaxb/JaxbService.java
@@ -26,6 +26,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
+import javax.annotation.Nullable;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Marshaller;
@@ -39,6 +40,8 @@ import org.apache.isis.core.commons.internal.base._Casts;
 import org.apache.isis.core.commons.internal.base._NullSafe;
 import org.apache.isis.core.commons.internal.collections._Maps;
 
+import lombok.NonNull;
+
 // tag::refguide[]
 public interface JaxbService {
 
@@ -131,13 +134,20 @@ public interface JaxbService {
         }
 
         protected Object internalFromXml(
-                final JAXBContext jaxbContext,
-                final String xml,
-                final Map<String, Object> unmarshallerProperties) throws JAXBException {
+                @NonNull final JAXBContext jaxbContext,
+                @Nullable final String xml,
+                @Nullable final Map<String, Object> unmarshallerProperties) throws JAXBException {
+            
+            if(xml==null) {
+                return null;
+            }
+            
             final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
 
-            for (Map.Entry<String, Object> entry : unmarshallerProperties.entrySet()) {
-                unmarshaller.setProperty(entry.getKey(), entry.getValue());
+            if(unmarshallerProperties!=null) {
+                for (Map.Entry<String, Object> entry : unmarshallerProperties.entrySet()) {
+                    unmarshaller.setProperty(entry.getKey(), entry.getValue());
+                }
             }
 
             configure(unmarshaller);
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/jaxb/JaxbServiceDefault.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/jaxb/JaxbServiceDefault.java
index ae574a6..e990777 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/jaxb/JaxbServiceDefault.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/jaxb/JaxbServiceDefault.java
@@ -37,8 +37,8 @@ import org.springframework.stereotype.Service;
 import org.apache.isis.applib.NonRecoverableException;
 import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.domain.DomainObjectList;
-import org.apache.isis.applib.jaxbadapters.PersistentEntitiesAdapter;
-import org.apache.isis.applib.jaxbadapters.PersistentEntityAdapter;
+import org.apache.isis.applib.jaxb.PersistentEntitiesAdapter;
+import org.apache.isis.applib.jaxb.PersistentEntityAdapter;
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.applib.services.metamodel.MetaModelService;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/queryresultscache/QueryResultsCache.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/queryresultscache/QueryResultsCache.java
index 6e22285..c0e6a75 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/queryresultscache/QueryResultsCache.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/queryresultscache/QueryResultsCache.java
@@ -21,6 +21,8 @@ package org.apache.isis.applib.services.queryresultscache;
 import java.util.Arrays;
 import java.util.concurrent.Callable;
 
+import org.springframework.beans.factory.DisposableBean;
+
 import org.apache.isis.applib.services.MethodReferences;
 
 import lombok.Data;
@@ -38,7 +40,7 @@ import lombok.Getter;
  * available for use; no further configuration is required.
  */
 // tag::refguide[]
-public interface QueryResultsCache {
+public interface QueryResultsCache extends DisposableBean {
 
     <T> T execute(                                      // <.>
             Callable<T> callable,
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/scratchpad/Scratchpad.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/scratchpad/Scratchpad.java
index 46553f9..3be13cd 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/scratchpad/Scratchpad.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/scratchpad/Scratchpad.java
@@ -24,6 +24,7 @@ import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 import javax.inject.Named;
 
+import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Primary;
 import org.springframework.core.annotation.Order;
@@ -46,7 +47,8 @@ import lombok.extern.log4j.Log4j2;
  * available for use; no further configuration is required.
  */
 // tag::refguide[]
-public interface Scratchpad {
+public interface Scratchpad
+        extends DisposableBean {
 
     // end::refguide[]
     /**
@@ -62,12 +64,6 @@ public interface Scratchpad {
     // tag::refguide[]
     public void put(Object key, Object value);
 
-    // end::refguide[]
-    /**
-     * Clear any user data.
-     */
-    // tag::refguide[]
-    public void clear();
 
 }
 // end::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/sudo/SudoService.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/sudo/SudoService.java
index f5e94e2..621828b 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/sudo/SudoService.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/sudo/SudoService.java
@@ -20,9 +20,8 @@
 package org.apache.isis.applib.services.sudo;
 
 import java.util.List;
-import java.util.concurrent.Callable;
+import java.util.function.Supplier;
 
-import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.services.user.UserService;
 
 /**
@@ -65,7 +64,7 @@ public interface SudoService {
     // tag::refguide[]
     <T> T sudo(                                             // <.>
             String username,
-            final Callable<T> callable);
+            final Supplier<T> supplier);
 
     // end::refguide[]
     /**
@@ -83,7 +82,7 @@ public interface SudoService {
     // tag::refguide[]
     <T> T sudo(                                             // <.>
             String username, List<String> roles,
-            final Callable<T> callable);
+            final Supplier<T> supplier);
 
     // end::refguide[]
 
@@ -96,7 +95,7 @@ public interface SudoService {
         // end::refguide-1[]
         /**
          * Any implementation of the {@link SudoService} should call this method on all implementations of the
-         * {@link Spi} service whenever {@link SudoService#sudo(String, List, Callable)} (or its overloads)
+         * {@link Spi} service whenever {@link SudoService#sudo(String, List, Supplier)} (or its overloads)
          * is called.
          *
          * <p>
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/tablecol/TableColumnOrderForCollectionTypeAbstract.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/tablecol/TableColumnOrderForCollectionTypeAbstract.java
new file mode 100644
index 0000000..4d604e3
--- /dev/null
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/tablecol/TableColumnOrderForCollectionTypeAbstract.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.applib.services.tablecol;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+
+// tag::refguide[]
+@RequiredArgsConstructor
+public abstract class TableColumnOrderForCollectionTypeAbstract<T>
+        implements TableColumnOrderService {
+
+    private final Class<T> collectionType;
+
+    public final List<String> orderParented(
+            final Object parent,
+            final String collectionId,
+            final Class<?> collectionType,
+            final List<String> propertyIds) {
+        if (!this.collectionType.isAssignableFrom(collectionType)) {
+            return propertyIds;
+        }
+        return orderParented(parent, collectionId, propertyIds);
+    }
+
+    protected List<String> orderParented(
+            final Object parent,
+            final String collectionId,
+            final List<String> propertyIds) {
+        return propertyIds;
+    }
+
+    public final List<String> orderStandalone(
+            final Class<?> collectionType,
+            final List<String> propertyIds) {
+        if (this.collectionType.isAssignableFrom(collectionType)) {
+            return propertyIds;
+        }
+        return orderStandalone(propertyIds);
+    }
+
+    protected List<String> orderStandalone(
+            final List<String> propertyIds) {
+        return propertyIds;
+    }
+
+}
+// end::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/wrapper/control/ControlAbstract.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/wrapper/control/ControlAbstract.java
index dc03213..0716096 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/wrapper/control/ControlAbstract.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/wrapper/control/ControlAbstract.java
@@ -20,6 +20,7 @@ package org.apache.isis.applib.services.wrapper.control;
 
 import java.lang.reflect.Method;
 import java.util.EnumSet;
+import java.util.Optional;
 
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.core.commons.collections.ImmutableEnumSet;
@@ -27,7 +28,6 @@ import org.apache.isis.core.commons.internal.base._Casts;
 
 import lombok.AccessLevel;
 import lombok.Getter;
-import lombok.NonNull;
 import lombok.Setter;
 
 // tag::refguide[]
@@ -67,14 +67,13 @@ public class ControlAbstract<T extends ControlAbstract<T>> {
         // tag::refguide[]
         // ...
     }
-
-    // end::refguide[]
-    /**
-     * Initialized in constructor.
-     */
-    // tag::refguide[]
-    @Getter @NonNull
-    private ExceptionHandler exceptionHandler;                  // <.>
+    
+    private ExceptionHandler exceptionHandler;
+   
+    public Optional<ExceptionHandler> getExceptionHandler() { // <.>
+        return Optional.ofNullable(exceptionHandler);
+    }
+                      
     public T with(ExceptionHandler exceptionHandler) {
         // end::refguide[]
         this.exceptionHandler = exceptionHandler;
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/xactn/TransactionService.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/xactn/TransactionService.java
index fb5d805..f308df4 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/xactn/TransactionService.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/xactn/TransactionService.java
@@ -85,23 +85,8 @@ public interface TransactionService {
      */
     // tag::refguide[]
     <T> T executeWithinTransaction(Supplier<T> task);       // <.>
-
     // end::refguide[]
 
-//   the executeWithinNewTransaction at time of writing is incorrect (doesn't create a new xactn).
-//   not sure there's any need for these additional methods?
-//
-//    /**
-//     * Runs given {@code task} within its own (new) transactional boundary.
-//     * @param task
-//     */
-//    void executeWithinNewTransaction(Runnable task);        // <.>
-//
-//    /**
-//     * Runs given {@code task} within its own (new) transactional boundary.
-//     * @param task
-//     */
-//    <T> T executeWithinNewTransaction(Supplier<T> task);    // <.>
 
     // tag::refguide[]
 }
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/BookmarkService.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/BookmarkService.adoc
index 65e7215..581b8b2 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/BookmarkService.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/BookmarkService.adoc
@@ -17,7 +17,6 @@ For example the xref:refguide:applib-svc:AuditerService.adoc[`AuditerService`] u
 
 Serialized form of bookmarks also appear within  xref:refguide:schema:about.adoc[schema] instances, for example as used by xref:refguide:applib-svc:CommandService.adoc[`CommandService`] and the xref:refguide:applib-svc:PublisherService.adoc[`PublisherService`].
 
-//Bookmarks are also used by the (non-ASF) link:https://platform.incode.org[Incode Platform^]'s command module's implementation of  xref:refguide:applib-svc:_BackgroundCommandService.adoc[`BackgroundCommandService`], which uses a bookmark to capture the target object on which an action will be invoked subsequently.
 
 
 == API
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/CommandContext.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/CommandContext.adoc
index a4fbcf1..a637936 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/CommandContext.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/CommandContext.adoc
@@ -4,6 +4,7 @@
 :page-partial:
 
 
+CAUTION: TODO v2 - to update, has been simplified
 
 The `CommandContext` service is a xref:refguide:applib-ant:IsisSessionScope.adoc[request-scoped] service that reifies the invocation of an action on a domain object into an object itself.
 This reified information is encapsulated within the xref:CommandContext.adoc#command[`Command`] object.
@@ -28,17 +29,6 @@ This is normally done using the `CommandWithDto` subtype, that can return a repr
 
 
 
-//== Screencast
-//
-//
-//The link:https://www.youtube.com/watch?v=tqXUZkPB3EI[screencast] provides a run-through of the command (profiling) service, auditing service, publishing service (note: auditing service has since been replaced by `AuditerService`, and publishing service by `PublisherService`).
-//It also shows how commands can be run in the background either explicitly by scheduling through the background service or implicitly by way of a framework annotation.
-//
-//
-//[NOTE]
-//====
-//Note that this screencast shows an earlier version of the xref:vw:ROOT:about.adoc[Wicket viewer] UI (specifically, pre 1.8.0).
-//====
 
 
 
@@ -63,7 +53,12 @@ include::refguide:applib-svc:example$services/command/Command.java[tags="refguid
 
 <.> user that initiated the action.
 <.> date/time at which this action was created.
-<.> bookmark of the target object (entity or service) on which this action was performed <.> holds a string representation of the invoked action <.> human-friendly description of the class of the target object <.> human-friendly name of the action invoked on the target object <.> human-friendly description of the arguments with which the action was invoked <.> formal (XML or similar) specification of the action to invoke/being invoked <.> whether this command is executed in the foregroun [...]
+<.> bookmark of the target object (entity or service) on which this action was performed
+<.> holds a string representation of the invoked action
+<.> human-friendly description of the class of the target object
+<.> human-friendly name of the action invoked on the target object
+<.> human-friendly description of the arguments with which the action was invoked <.> formal (XML or similar) specification of the action to invoke/being invoked
+<.> whether this command is executed in the foreground or background
 +
 [source,java,indent=0]
 ----
@@ -110,23 +105,6 @@ public class ToDoItem ... {
 As an alternative to annotating every action with xref:refguide:applib-ant:Action.adoc#command[`@Action#command()`], use the xref:refguide:config:sections/isis.applib.adoc#isis.applib.annotation.action.command[`isis.applib.annotation.action.command`] to define a global default.
 
 
-//The xref:refguide:applib-ant:Action.adoc#command[`@Action#command()`] annotation can also be used to specify whether the command should be performed in the background, for example:
-//
-//[source,java]
-//----
-//public class ToDoItem ... {
-//    @Action(commandExecuteIn=CommandExecuteIn.BACKGROUND)
-//    public ToDoItem scheduleImplicitly() {
-//        completeSlowly(3000);
-//        return this;
-//    }
-//}
-//----
-//
-//When a background command is invoked, the user is returned the command object itself (to provide a handle to the command being invoked).
-//
-//This requires that an implementation of xref:refguide:applib-svc:CommandService.adoc[`CommandService`] that persists the commands (such as the (non-ASF) link:https://platform.incode.org[Incode Platform^]'s command module's `CommandService`) is configured.
-//It also requires that a scheduler is configured to execute the background commands, see xref:refguide:applib-svc:_BackgroundCommandService.adoc[`BackgroundCommandService`]).
 
 
 
@@ -186,14 +164,10 @@ public class ToDoItem ... {
 The implementation of xref:refguide:applib-svc:CommandContext.adoc#command[`Command`] is provided by the xref:refguide:applib-svc:CommandService.adoc[`CommandService`].
 The default implementation of that service creates an in-memory instance, but other implementations might choose to persist the `Command`, eg so its execution can be deferred, or replayed.
 
-//Implementations of `CommandService` and `BackgroundCommandService` are intended to go together, so that child ``Command``s persistent (to be executed in the background) can be associated with their parent ``Command``s (executed in the foreground, with the background `Command` created explicitly through the xref:refguide:applib-svc:BackgroundService.adoc[`BackgroundService`]).
 
 The xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] service itself is very similar in nature to the xref:refguide:applib-svc:InteractionContext.adoc[`InteractionContext`], in that the `Command` object accessed through it is very similar to the xref:refguide:applib-svc:InteractionContext.adoc#interaction[`Interaction`] object obtained from the `InteractionContext`.
 The principle distinction is that while `Command` represents the __intention__ to invoke an action or edit a property, the `Interaction` (and contained ``Execution``s) represents the actual execution.
 
-//Most of the time a `Command` will be followed directly by its corresponding `Interaction`.
-//However, if the `Command` is annotated to run in the background (using xref:refguide:applib-ant:Action.adoc#command[`@Action#commandExecuteIn()`], or is explicitly created through the xref:refguide:applib-svc:BackgroundService.adoc[`BackgroundService`], then the actual interaction/execution is deferred until some other mechanism invokes the command (eg as described xref:userguide:btb:about.adoc#BackgroundCommandExecution[here]).
-//The persistence of background commands requires a configured xref:refguide:applib-svc:_BackgroundCommandService.adoc[`BackgroundCommandService`]) to actually persist such commands for execution.
 
 
 ``Command``s are often combined with implementations of the xref:refguide:applib-svc:PublisherService.adoc[`PublisherService`] and sometimes also the xref:refguide:applib-svc:AuditerService.adoc[`AuditerService`]:
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/CommandService.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/CommandService.adoc
index 2b8d4bf..2f97605 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/CommandService.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/CommandService.adoc
@@ -4,9 +4,9 @@
 :page-partial:
 
 
-The `CommandService` service supports the xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] service such that xref:refguide:applib-svc:CommandContext.adoc#command[`Command`] objects (that reify the invocation of an action/edit of a property on a domain object) can be persisted.
+CAUTION: TODO - v2 - to update, has been simplified.
 
-//The primary use case for persistent ``Command``s is in support of background commands; they act as a parent to any background commands that can be persisted either explicitly using the xref:refguide:applib-svc:BackgroundService.adoc[`BackgroundService`], or implicitly by way of the xref:refguide:applib-ant:Action.adoc#command[`@Action#command()`] annotation.
+The `CommandService` service supports the xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] service such that xref:refguide:applib-svc:CommandContext.adoc#command[`Command`] objects (that reify the invocation of an action/edit of a property on a domain object) can be persisted.
 
 ``Command``s
 //also
@@ -27,7 +27,7 @@ The `CommandService` service defines the following very simple API:
 
 [source,java]
 ----
-include::refguide:applib-svc:example$services/command/spi/CommandService.java[tags="refguide"]
+include::refguide:applib-svc:example$services/command/CommandService.java[tags="refguide"]
 ----
 
 <.> Instantiate the appropriate instance of the xref:refguide:applib-svc:CommandContext.adoc#command[`Command`] (as defined by the
@@ -44,9 +44,6 @@ The xref:extensions:command-log:about.adoc[Command Log] extension provides an im
 == Related Services
 
 As discussed above, this service supports the xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`], providing the ability for `Command` objects to be persisted.
-//This is closely related to the xref:refguide:applib-svc:_BackgroundCommandService.adoc[`BackgroundCommandService`]that allows the xref:refguide:applib-svc:BackgroundService.adoc[`BackgroundService`] to schedule commands for background/asynchronous execution.
-
-//The implementations of `CommandService` and `BackgroundCommandService` are intended to go together, so that persistent parent `Command`s can be associated with their child background `Command`s.
 
 The services provided by this module combines very well with the xref:refguide:applib-svc:AuditerService.adoc[`AuditerService`].
 The `CommandService` captures the __cause__ of an interaction (an action was invoked, a property was edited), while the `AuditerService` captures the __effect__ of that interaction in terms of changed state.
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundCommandService.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundCommandService.adoc
deleted file mode 100644
index 62f50c8..0000000
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundCommandService.adoc
+++ /dev/null
@@ -1,107 +0,0 @@
-= `BackgroundCommandService2`
-
-:Notice: 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 ag [...]
-:page-partial:
-
-WARNING: TODO: v2 - temporarily removed, to be reinstated in v2.0
-
-The `BackgroundCommandService2` (SPI) service supports the xref:refguide:applib-svc:BackgroundService.adoc[`BackgroundService`] (API) service, persisting action invocations as commands such that they can subsequently be invoked in the background.
-
-The `BackgroundService` is responsible for capturing a memento representing the action invocation, and then hands off to the xref:refguide:applib-svc:BackgroundCommandService.adoc[`BackgroundCommandService`] `BackgroundCommandService` to actually persist it.
-
-The persisting of commands is only half the story; there needs to be a separate process to read the commands and execute them.
-The abstract xref:refguide:applib-svc:BackgroundCommandExecution.adoc[`BackgroundCommandExecution`] provides a mechanism to execute such commands.  This can be considered an API, albeit "internal" because the implementation relies on internals of the framework.
-
-
-
-
-== SPI
-
-The SPI of the `BackgroundCommandService2` is:
-
-[source,java]
-----
-public interface BackgroundCommandService2 {
-    void schedule(
-            CommandDto dto,             // <1>
-            Command parentCommand,      // <2>
-            String targetClassName,
-            String targetActionName,
-            String targetArgs);
-
-}
-----
-<1> an instance of a xref:refguide:schema:cmd.adoc[`CommandDto`] capturing the details of the action invocation or property edit to be retained (eg persisted to a database) so that it can be executed at a later time
-<2> reference to the parent `Command` requesting the action be performed as a background command.  This allows information such as the initiating user to be obtained.
-
-
-
-== "Internal" SPI
-
-The `BackgroundCommandExecution` (in isis-core) is an abstract template class for  xref:userguide:btb:about.adoc#AbstractIsisSessionTemplate[headless access], that defines an abstract hook method to obtain background `Command`s to be executed:
-
-[source,java]
-----
-public abstract class BackgroundCommandExecution
-                         extends AbstractIsisSessionTemplate {
-    ...
-    protected abstract List<? extends Command> findBackgroundCommandsToExecute();
-    ...
-}
-----
-
-The developer is required to implement this hook method in a subclass.
-
-
-
-
-== Implementation
-
-The (non-ASF) link:https://platform.incode.org[Incode Platform^]'s command module provides an implementation (`org.isisaddons.module.command.dom.BackgroundCommandServiceJdo`) that persists ``Command``s using the JDO/DataNucleus object store.
-It further provides a number of supporting services:
-
-* `org.isisaddons.module.command.dom.BackgroundCommandServiceJdoRepository` is a repository to search for persisted background ``Command``s
-
-* `org.isisaddons.module.command.dom.BackgroundCommandServiceJdoContributions` contributes actions for searching for persisted child and sibling ``Command``s.
-
-The module also provides a concrete subclass of `BackgroundCommandExecution` that knows how to query for persisted (background) `Command`s such that they can be executed by a scheduler.
-
-[TIP]
-====
-Details of setting up the Quartz scheduler to actually execute these persisted commands can be found on the xref:refguide:applib-svc:BackgroundService.adoc[`BackgroundService`] page.
-====
-
-
-
-
-== Usage
-
-Background commands can be created either declaratively or imperatively.
-
-The declarative approach involves annotating an action using xref:refguide:applib-ant:Action.adoc#command[`@Action#command()`] with `@Action#commandExecuteIn=CommandExecuteIn.BACKGROUND`.
-
-The imperative approach involves explicitly calling the xref:refguide:applib-svc:BackgroundService.adoc[`BackgroundService`] from within domain object's action.
-
-
-
-
-== Alternative Implementations
-
-The (non-ASF) link:https://platform.incode.org[Incode Platform^]'s command module provides an implementation of this service (`BackgroundCommandService`), and also provides a number of related domain services (`BackgroundCommandServiceJdo`, `BackgroundCommandJdoRepository` and `BackgroundCommandServiceJdoContributions`).
-This module also provides service implementations of the xref:refguide:applib-svc:CommandService.adoc[`CommandService`].
-
-If contributions are not required in the UI, these can be suppressed either using security or by implementing a xref:userguide:btb:about.adoc#vetoing-visibility[vetoing subscriber].
-
-
-
-
-== Related Services
-
-As discussed above, this service supports the xref:refguide:applib-svc:BackgroundService.adoc[`BackgroundService`] , persisting `Command`s such that they can be executed in the background.
-
-There is also a tie-up with the xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] and its supporting xref:refguide:applib-svc:CommandService.adoc[`CommandService`] domain service. The `CommandContext` service is responsible for providing a parent `Command` with which the background `Command`s can then be associated as children, while the `CommandService` is responsible for persisting those parent `Command`s (analogous to the way in which the `BackgroundCommandService` persis [...]
-
-What that means is that the implementations of `CommandService` and `BackgroundCommandService` go together, hence both implemented in the (non-ASF) link:https://platform.incode.org[Incode Platform^]'s  command module.).
-
-
-
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundService.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundService.adoc
deleted file mode 100644
index 6642f4b..0000000
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundService.adoc
+++ /dev/null
@@ -1,120 +0,0 @@
-= `BackgroundService`
-
-:Notice: 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 ag [...]
-:page-partial:
-
-WARNING: TODO: v2 - temporarily removed, will be reinstated for v2.0
-
-The `BackgroundService` domain service (and its various supertypes), and also the companion xref:refguide:applib-svc:BackgroundCommandService.adoc[`BackgroundCommandService2`] SPI service, enable commands to be persisted such that they may be invoked in the background.
-
-The `BackgroundService` is responsible for capturing a memento representing the command in a typesafe way, and persisting it rather than executing it directly.
-
-The default `BackgroundServiceDefault` implementation works by using a proxy wrapper around the target so that it can capture the action to invoke and its arguments.
-
-This is done using xref:core:runtime-services:CommandDtoServiceInternal.adoc[`CommandDtoServiceInternal`].
-
-The persistence delegates the persistence of the memento to an appropriate implementation of the companion `BackgroundCommandService2`.
-One such implementation of `BackgroundCommandService` is provided by (non-ASF) http://github.com/incodehq/incode-platform[Incode Platform's command] module.
-
-The persisting of commands is only half the story; there needs to be a separate process to read the commands and execute them.
-The `BackgroundCommandExecution` abstract class (discussed xref:refguide:applib-svc:BackgroundCommandExecution.adoc[below]) provides infrastructure to do this; the concrete implementation of this class depends on the configured `BackgroundCommandService` (in order to query for the persisted (background) ``Command``s.
-
-
-
-== API & Implementation
-
-The API is:
-
-[source,java]
-----
-public interface BackgroundService {
-    <T> T execute(final T object);                              // <1>
-    <T> T executeMixin(Class<T> mixinClass, Object mixedIn);    // <2>
-}
-----
-<1> returns a proxy around the domain object; any methods executed against this proxy will result in a command (to invoke the corresponding action) being persisted by xref:refguide:applib-svc:BackgroundCommandService2.adoc[`BackgroundCommandService2`]
-<2> Returns a proxy around the mixin; any methods executed against this proxy will result in a command (to invoke the corresponding mixin action) being persisted by xref:refguide:applib-svc:BackgroundCommandService2.adoc[`BackgroundCommandService2`].
-
-The default implementation is provided by core (`o.a.i.core.runtime.services.background.BackgroundServiceDefault`).
-
-To provide an alternative implementation, subclass and link:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/annotation/Order.html[`@Order`] or equivalent (as explained in the xref:refguide:applib-svc:about.adoc#overriding-the-services[introduction] to this guide).
-
-
-== Usage
-
-Using the service is very straight-forward; wrap the target domain object using `BackgroundService#execute(...)` and invoke the method on the object returned by that method.
-
-For example:
-
-[source,java]
-----
-public void submitCustomerInvoices() {
-    for(Customer customer: customerRepository.findCustomersToInvoice()) {
-        backgroundService.execute(customer).submitInvoice();
-    }
-    messageService.informUser("Calculating...");
-}
-----
-
-This will create a bunch of background commands executing the `submitInvoice()` action for each of the customers returned from the customer repository.
-
-The action method invoked must be part of the Apache Isis metamodel, which is to say it must be public, accept only scalar arguments, and must not be annotated with xref:refguide:applib-ant:Programmatic.adoc[`@Programmatic`] or `@Ignore`.
-However, it may be annotated with xref:refguide:applib-ant:Action.adoc#hidden[`@Action#hidden()`] or xref:refguide:applib-ant:ActionLayout.adoc#hidden[`@ActionLayout#hidden()`] and it will still be invoked.
-
-In fact, when invoked by the background service, no business rules (hidden, disabled, validation) are enforced; the action method must take responsibility for performing appropriate validation and error checking.
-
-[TIP]
-====
-If you want to check business rules, you can use xref:refguide:applib-ant:WrapperFactory.adoc[`@WrapperFactory#wrapNoExecute(...)`].
-====
-
-
-
-== End-user experience
-
-For the end-user, executing an action that delegates work off to the `BackgroundService` raises the problem of how does the user know the work is complete?
-
-One option is for the background jobs to take responsibility to notify the user themselves.
-In the above example, this would be the `submitInvoice()` method called upon each customer.
-One could imagine more complex designs where only the final command executed notifies the user.
-
-However, an alternative is to rely on the fact that the `BackgroundService` will automatically hint that the `Command` representing the original interaction (to `submitCustomerInvoices()` in the example above) should be persisted.
-This will be available if the related xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] and xref:refguide:applib-svc:CommandService.adoc[`CommandService`] domain services are configured, and the `CommandService` supports persistent commands.
-Note that (non-ASF) link:https://platform.incode.org[Incode Platform^]'s command module does indeed provide such an implementation of `CommandService` (as well as of the required `BackgroundCommandService`).
-
-Thus, the original action can run a query to obtain it corresponding `Command`, and return this to the user.
-The upshot is that the child ``Command``s created by the `BackgroundService` will then be associated with `Command` for the original action.
-
-We could if we wanted write the above example as follows:
-
-[source,java]
-----
-public Command submitCustomerInvoices() {
-    for(Customer customer: customerRepository.findCustomersToInvoice()) {
-        backgroundService.execute(customer).submitInvoice();
-    }
-    return commandContext.getCommand();
-}
-@Inject
-CommandContext commandContext;  // <1>
-----
-<1> the injected xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] domain service.
-
-The user would be returned a domain object representing their action invocation.
-
-
-
-
-== Related Services
-
-This service is closely related to the xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] and also that service's supporting xref:refguide:applib-svc:CommandService.adoc[`CommandService`] service.
-
-The `CommandContext` service is responsible for providing a parent `Command` with which the background ``Command``s can then be associated as children, while the `CommandService` is responsible for persisting those parent `Command`s.
-The latter is analogous to the way in which the `BackgroundCommandService` persists the child background `Command`s.
-
-The implementations of `CommandService` and `BackgroundCommandService` go together; typically both parent `Command`s and child background `Command`s will be persisted in the same way.
-The (non-ASF) link:https://platform.incode.org[Incode Platform^]'s command module provides implementations of both (see xref:refguide:applib-svc:CommandService.adoc[`CommandService`] and xref:refguide:applib-svc:BackgroundCommandService.adoc[`BackgroundCommandService`]).
-
-The xref:core:runtime-services:CommandDtoServiceInternal.adoc[`CommandDtoServiceInternal`] is used to obtain a memento of the command such that it can be persisted.
-
-
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundService/_Quartz.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundService/_Quartz.adoc
deleted file mode 100644
index 14d1859..0000000
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundService/_Quartz.adoc
+++ /dev/null
@@ -1,165 +0,0 @@
-[[Quartz]]
-= Quartz Scheduler Configuration
-
-:Notice: 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 ag [...]
-:page-partial:
-
-WARNING: TODO: v2 - background command execution temporarily removed, will be reinstated for v2.0
-
-The last part of the puzzle is to actually run the (appropriate implementation of) `BackgroundCommandExecution`).
-This could be run in a batch job overnight, or run continually by, say, the http://quartz-scheduler.org[Quartz] scheduler or by link:http://camel.apache.org[Apache Camel].
-This section looks at configuring Quartz.
-
-If using (non-ASF) link:https://platform.incode.org[Incode Platform^]'s command module, then note that this already provides a suitable concrete implementation, namely `org.isisaddons.module.command.dom.BackgroundCommandExecutionFromBackgroundCommandServiceJdo`.
-We therefore just need to schedule this to run as a Quartz job.
-
-
-First, we need to define a Quartz job, for example:
-
-[source,java]
-----
-import org.isisaddons.module.command.dom.BackgroundCommandExecutionFromBackgroundCommandServiceJdo;
-public class BackgroundCommandExecutionQuartzJob extends AbstractIsisQuartzJob {
-    public BackgroundCommandExecutionQuartzJob() {
-        super(new BackgroundCommandExecutionFromBackgroundCommandServiceJdo());
-    }
-}
-----
-
-where `AbstractIsisQuartzJob` is in turn the following boilerplate:
-
-[source,java]
-----
-package domainapp.webapp.quartz;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-import org.quartz.JobExecutionException;
-...
-public class AbstractIsisQuartzJob implements Job {
-    public static enum ConcurrentInstancesPolicy {
-        SINGLE_INSTANCE_ONLY,
-        MULTIPLE_INSTANCES
-    }
-
-    private final AbstractIsisSessionTemplate isisRunnable;
-    private final ConcurrentInstancesPolicy concurrentInstancesPolicy;
-    private boolean executing;
-
-    public AbstractIsisQuartzJob(AbstractIsisSessionTemplate isisRunnable) {
-        this(isisRunnable, ConcurrentInstancesPolicy.SINGLE_INSTANCE_ONLY);
-    }
-    public AbstractIsisQuartzJob(
-            AbstractIsisSessionTemplate isisRunnable,
-            ConcurrentInstancesPolicy concurrentInstancesPolicy) {
-        this.isisRunnable = isisRunnable;
-        this.concurrentInstancesPolicy = concurrentInstancesPolicy;
-    }
-
-    public void execute(final JobExecutionContext context)
-            throws JobExecutionException {
-        final AuthenticationSession authSession = newAuthSession(context);
-        try {
-            if(concurrentInstancesPolicy == ConcurrentInstancesPolicy.SINGLE_INSTANCE_ONLY &&
-               executing) {
-                return;
-            }
-            executing = true;
-
-            isisRunnable.execute(authSession, context);
-        } finally {
-            executing = false;
-        }
-    }
-
-    AuthenticationSession newAuthSession(JobExecutionContext context) {
-        String user = getKey(context, SchedulerConstants.USER_KEY);
-        String rolesStr = getKey(context, SchedulerConstants.ROLES_KEY);
-        String[] roles = Iterables.toArray(
-                Splitter.on(",").split(rolesStr), String.class);
-        return new SimpleSession(user, roles);
-    }
-
-    String getKey(JobExecutionContext context, String key) {
-        return context.getMergedJobDataMap().getString(key);
-    }
-}
-----
-
-
-This job can then be configured to run using Quartz' `quartz-config.xml` file:
-
-[source,xml]
-----
-<?xml version="1.0" encoding="UTF-8"?>
-<job-scheduling-data
-    xmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData
-http://www.quartz-scheduler.org/xml/job_scheduling_data_1_8.xsd"
-    version="1.8">
-    <schedule>
-       <job>
-         <name>BackgroundCommandExecutionJob</name>
-         <group>Isis</group>
-         <description>
-                Poll and execute any background actions persisted by the BackgroundActionServiceJdo domain service
-            </description>
-         <job-class>domainapp.webapp.quartz.BackgroundCommandExecutionQuartzJob</job-class>
-         <job-data-map>
-          <entry>
-              <key>webapp.scheduler.user</key>
-              <value>scheduler_user</value>
-          </entry>
-          <entry>
-              <key>webapp.scheduler.roles</key>
-              <value>admin_role</value>
-          </entry>
-         </job-data-map>
-       </job>
-       <trigger>
-         <cron>
-          <name>BackgroundCommandExecutionJobEveryTenSeconds</name>
-          <job-name>BackgroundCommandExecutionJob</job-name>
-          <job-group>Isis</job-group>
-          <cron-expression>0/10 * * * * ?</cron-expression>
-         </cron>
-       </trigger>
-    </schedule>
-</job-scheduling-data>
-----
-
-The remaining two pieces of configuration are the `quartz.properties` file:
-
-[source,ini]
-----
-org.quartz.scheduler.instanceName = SchedulerQuartzConfigXml
-org.quartz.threadPool.threadCount = 1
-org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
-org.quartz.plugin.jobInitializer.class =org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
-org.quartz.plugin.jobInitializer.fileNames = webapp/scheduler/quartz-config.xml
-org.quartz.plugin.jobInitializer.failOnFileNotFound = true
-----
-
-and the entry in `web.xml` for the Quartz servlet:
-
-[source,xml]
-----
-<servlet>
-     <servlet-name>QuartzInitializer</servlet-name>
-     <servlet-class>org.quartz.ee.servlet.QuartzInitializerServlet</servlet-class>
-     <init-param>
-         <param-name>config-file</param-name>
-         <param-value>webapp/scheduler/quartz.properties</param-value>
-     </init-param>
-     <init-param>
-         <param-name>shutdown-on-unload</param-name>
-         <param-value>true</param-value>
-     </init-param>
-     <init-param>
-         <param-name>start-scheduler-on-load</param-name>
-         <param-value>true</param-value>
-     </init-param>
-     <load-on-startup>1</load-on-startup>
- </servlet>
-----
-
diff --git a/api/applib/src/main/adoc/modules/applib-svc/partials/module-nav.adoc b/api/applib/src/main/adoc/modules/applib-svc/partials/module-nav.adoc
index 54691db..f95b4fc 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/partials/module-nav.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/partials/module-nav.adoc
@@ -6,10 +6,6 @@
 ** xref:refguide:applib-svc:AcceptHeaderService.adoc[AcceptHeaderService]
 ** xref:refguide:applib-svc:ApplicationFeatureRepository.adoc[ApplicationFeatureRepository]
 ** xref:refguide:applib-svc:AuditerService.adoc[AuditerService]
-//** xref:refguide:applib-svc:_BackgroundCommandService.adoc[BackgroundCommandService]
-//** xref:refguide:applib-svc:_BackgroundService.adoc[BackgroundService]
-//*** xref:refguide:applib-svc:_BackgroundCommandExecution.adoc[BackgroundCommandExecution]
-//*** xref:refguide:applib-svc:_Quartz.adoc[Quartz]
 ** xref:refguide:applib-svc:BookmarkService.adoc[BookmarkService]
 ** xref:refguide:applib-svc:BookmarkUiService.adoc[BookmarkUiService]
 ** xref:refguide:applib-svc:ClockService.adoc[ClockService]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/IsisModuleApplib.java b/api/applib/src/main/java/org/apache/isis/applib/IsisModuleApplib.java
index 61dc1cb..c68a0b5 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/IsisModuleApplib.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/IsisModuleApplib.java
@@ -34,6 +34,7 @@ import org.apache.isis.applib.services.bookmark.BookmarkHolder_lookup;
 import org.apache.isis.applib.services.bookmark.BookmarkHolder_object;
 import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.command.CommandContext;
+import org.apache.isis.applib.services.command.CommandService;
 import org.apache.isis.applib.services.confview.ConfigurationMenu;
 import org.apache.isis.applib.services.conmap.command.ContentMappingServiceForCommandDto;
 import org.apache.isis.applib.services.conmap.command.ContentMappingServiceForCommandsDto;
@@ -72,6 +73,7 @@ import org.apache.isis.schema.IsisModuleSchema;
         AuditerServiceLogging.class,
         ClockService.class,
         CommandContext.class,
+        CommandService.class,
         ContentMappingServiceForCommandDto.class,
         ContentMappingServiceForCommandsDto.class,
         InteractionContext.class,
diff --git a/api/applib/src/main/java/org/apache/isis/applib/annotation/Action.java b/api/applib/src/main/java/org/apache/isis/applib/annotation/Action.java
index c73d945..12583cd 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/annotation/Action.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/annotation/Action.java
@@ -27,8 +27,7 @@ import java.lang.annotation.Target;
 
 import org.apache.isis.applib.events.domain.ActionDomainEvent;
 import org.apache.isis.applib.services.command.CommandDtoProcessor;
-import org.apache.isis.applib.services.command.CommandWithDto;
-import org.apache.isis.applib.services.command.spi.CommandService;
+import org.apache.isis.applib.services.command.CommandService;
 import org.apache.isis.applib.services.conmap.command.ContentMappingServiceForCommandDto;
 import org.apache.isis.applib.services.conmap.command.ContentMappingServiceForCommandsDto;
 import org.apache.isis.applib.value.Blob;
@@ -99,29 +98,6 @@ public @interface Action {
 
     // end::refguide[]
     /**
-     * How the {@link org.apache.isis.applib.services.command.Command Command} object provided by the
-     * {@link org.apache.isis.applib.services.command.CommandContext CommandContext} domain service should be persisted.
-     */
-    // tag::refguide[]
-    CommandPersistence commandPersistence()                         // <.>
-            default CommandPersistence.PERSISTED;
-
-    // end::refguide[]
-    /**
-     * How the command/action should be executed.
-     *
-     * <p>
-     * If the corresponding {@link org.apache.isis.applib.services.command.Command Command} object is persisted,
-     * then its {@link org.apache.isis.applib.services.command.Command#getExecuteIn() invocationType} property
-     * will be set to this value.
-     * </p>
-     */
-    // tag::refguide[]
-    CommandExecuteIn commandExecuteIn()                             // <.>
-            default CommandExecuteIn.FOREGROUND;
-
-    // end::refguide[]
-    /**
      * The {@link CommandDtoProcessor} to process this command's DTO.
      *
      * <p>
diff --git a/api/applib/src/main/java/org/apache/isis/applib/annotation/CommandExecuteIn.java b/api/applib/src/main/java/org/apache/isis/applib/annotation/CommandExecuteIn.java
deleted file mode 100644
index 14afaed..0000000
--- a/api/applib/src/main/java/org/apache/isis/applib/annotation/CommandExecuteIn.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.applib.annotation;
-
-/**
- * Whether a command should be executed immediately and synchronously in the foreground or rather should only be
- * persisted (such that it can be executed asynchronously in the background by some other mechanism).
- *
- * <p>
- *     Note: this enum is <i>not</i> an inner class of the {@link org.apache.isis.applib.annotation.Action} annotation
- *     because in the future we may also support commands for {@link org.apache.isis.applib.annotation.Property} and
- *     {@link org.apache.isis.applib.annotation.Collection}.
- * </p>
- */
-// tag::refguide[]
-public enum CommandExecuteIn {
-    // end::refguide[]
-    /**
-     * Execute synchronously in the &quot;foreground&quot;, wait for the results.
-     */
-    // tag::refguide[]
-    FOREGROUND,
-    // end::refguide[]
-    /**
-     * Execute &quot;asynchronously&quot; through the {@link org.apache.isis.applib.services.background.BackgroundCommandService}, returning (if possible) the
-     * persisted {@link org.apache.isis.applib.services.command.Command command} object as a placeholder to the
-     * result.
-     */
-    // tag::refguide[]
-    BACKGROUND,
-    // end::refguide[]
-    /**
-     * For commands that are replicated from a master onto a slave and are to be replayed (typically using the same
-     * mechanism as "regular" background commands, eg a background job).
-     *
-     * <p>
-     *     For framework use, not intended to be used in application code.
-     * </p>
-     */
-    // tag::refguide[]
-    REPLAYABLE,
-    // end::refguide[]
-    /**
-     * For commands that have been excluded and will not run.
-     * These are typically for a replayable command that has hit an exception (which normally would prevent any further
-     * replayable commands from being replayed) and which the administrator has decided to skip.
-     */
-    // tag::refguide[]
-    EXCLUDED
-    // end::refguide[]
-    ;
-
-    public boolean isForeground() { return this == FOREGROUND; }
-    public boolean isBackground() { return this == BACKGROUND; }
-    public boolean isReplayable() { return this == REPLAYABLE; }
-    public boolean isExcluded() { return this == EXCLUDED; }
-
-    public static class Type {
-        private Type() {}
-        public static class Meta {
-            public static final int MAX_LEN = 10;
-            private Meta() {}
-        }
-    }
-    // tag::refguide[]
-}
-// end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/annotation/CommandPersistence.java b/api/applib/src/main/java/org/apache/isis/applib/annotation/CommandPersistence.java
deleted file mode 100644
index 7f7000a..0000000
--- a/api/applib/src/main/java/org/apache/isis/applib/annotation/CommandPersistence.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.applib.annotation;
-
-/**
- * Whether the command should be persisted.
- */
-// tag::refguide[]
-public enum CommandPersistence {
-
-    // end::refguide[]
-    /**
-     * (If the configured {@link org.apache.isis.applib.services.command.spi.CommandService} supports it), indicates that the
-     * {@link org.apache.isis.applib.services.command.Command Command} object should be persisted.
-     */
-    // tag::refguide[]
-    PERSISTED,
-    // end::refguide[]
-    /**
-     * (If the configured {@link org.apache.isis.applib.services.command.spi.CommandService} supports it), indicates that the
-     * {@link org.apache.isis.applib.services.command.Command Command} object should only be persisted if
-     * another service, such as the {@link org.apache.isis.applib.services.background.BackgroundCommandService}, hints that it should.
-     */
-    // tag::refguide[]
-    IF_HINTED,
-    // end::refguide[]
-    /**
-     * (Even if the configured {@link org.apache.isis.applib.services.command.spi.CommandService} supports it), indicates that the
-     * {@link org.apache.isis.applib.services.command.Command Command} object should <i>not</i> be persisted (even if
-     * another service, such as the {@link org.apache.isis.applib.services.background.BackgroundCommandService}, hints that it should).
-     */
-    // tag::refguide[]
-    NOT_PERSISTED
-
-}
-// end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/annotation/Property.java b/api/applib/src/main/java/org/apache/isis/applib/annotation/Property.java
index ac40f2d..5393e2c 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/annotation/Property.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/annotation/Property.java
@@ -27,8 +27,6 @@ import java.lang.annotation.Target;
 
 import org.apache.isis.applib.events.domain.PropertyDomainEvent;
 import org.apache.isis.applib.services.command.CommandDtoProcessor;
-import org.apache.isis.applib.services.command.CommandWithDto;
-import org.apache.isis.applib.services.command.spi.CommandService;
 import org.apache.isis.applib.services.conmap.command.ContentMappingServiceForCommandDto;
 import org.apache.isis.applib.services.conmap.command.ContentMappingServiceForCommandsDto;
 import org.apache.isis.applib.spec.Specification;
@@ -52,7 +50,8 @@ public @interface Property {
 
     // end::refguide[]
     /**
-     * Whether the property edit should be reified into a {@link org.apache.isis.applib.services.command.Command} object.
+     * Whether the property edit should be reified into a
+     * {@link org.apache.isis.applib.services.command.Command} object.
      */
     // tag::refguide[]
     CommandReification command()                                // <.>
@@ -60,39 +59,10 @@ public @interface Property {
 
     // end::refguide[]
     /**
-     * How the {@link org.apache.isis.applib.services.command.Command Command} object provided by the
-     * {@link org.apache.isis.applib.services.command.CommandContext CommandContext} domain service should be persisted.
-     */
-    // tag::refguide[]
-    CommandPersistence commandPersistence()                     // <.>
-            default CommandPersistence.PERSISTED;
-
-    // end::refguide[]
-    /**
-     * How the command/property edit should be executed.
-     *
-     * <p>
-     * If the corresponding {@link org.apache.isis.applib.services.command.Command Command} object is persisted,
-     * then its {@link org.apache.isis.applib.services.command.Command#getExecuteIn() invocationType} property
-     * will be set to this value.
-     * </p>
-     */
-    // tag::refguide[]
-    CommandExecuteIn commandExecuteIn()                         // <.>
-            default CommandExecuteIn.FOREGROUND;
-
-    // end::refguide[]
-    /**
      * The {@link CommandDtoProcessor} to process this command's DTO.
      *
      * <p>
-     *     Specifying a processor requires that the implementation of {@link CommandService} provides a
-     *     custom implementation of {@link org.apache.isis.applib.services.command.Command} that additional extends
-     *     from {@link CommandWithDto}.
-     * </p>
-     *
-     * <p>
-     *     Tprocessor itself is used by {@link ContentMappingServiceForCommandDto} and
+     *     The processor itself is used by {@link ContentMappingServiceForCommandDto} and
      *     {@link ContentMappingServiceForCommandsDto} to dynamically transform the DTOs.
      * </p>
      */
@@ -210,7 +180,7 @@ public @interface Property {
      *
      * <p>
      *     For properties the default value, {@link org.apache.isis.applib.annotation.Optionality#DEFAULT}, usually
-     *     means that the property is required unless it has been overridden by {@link javax.jdo.annotations.Column}
+     *     means that the property is required unless it has been overridden by <code>javax.jdo.annotations.Column</code>
      *     with its <code>javax.jdo.annotations.Column#allowsNull()</code> attribute set to true.
      * </p>
      */
diff --git a/api/applib/src/main/java/org/apache/isis/applib/mixins/layout/Object_rebuildMetamodel.java b/api/applib/src/main/java/org/apache/isis/applib/mixins/layout/Object_rebuildMetamodel.java
index 506c7a7..c68f875 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/mixins/layout/Object_rebuildMetamodel.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/mixins/layout/Object_rebuildMetamodel.java
@@ -22,7 +22,6 @@ import javax.inject.Inject;
 
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.ActionLayout;
-import org.apache.isis.applib.annotation.CommandPersistence;
 import org.apache.isis.applib.annotation.Contributed;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.Mixin;
@@ -33,7 +32,15 @@ import org.apache.isis.applib.services.metamodel.MetaModelService;
 
 import lombok.RequiredArgsConstructor;
 
-@Mixin(method="act") 
+@Action(
+        domainEvent = Object_rebuildMetamodel.ActionDomainEvent.class,
+        semantics = SemanticsOf.IDEMPOTENT,
+        restrictTo = RestrictTo.PROTOTYPING
+)
+@ActionLayout(
+        cssClassFa = "fa-sync",
+        position = ActionLayout.Position.PANEL
+)
 @RequiredArgsConstructor
 public class Object_rebuildMetamodel {
 
@@ -42,17 +49,6 @@ public class Object_rebuildMetamodel {
     public static class ActionDomainEvent
     extends org.apache.isis.applib.IsisModuleApplib.ActionDomainEvent<Object_rebuildMetamodel> {}
 
-    @Action(
-            domainEvent = ActionDomainEvent.class,
-            semantics = SemanticsOf.IDEMPOTENT,
-            commandPersistence = CommandPersistence.NOT_PERSISTED,
-            restrictTo = RestrictTo.PROTOTYPING
-            )
-    @ActionLayout(
-            contributed = Contributed.AS_ACTION,
-            cssClassFa = "fa-sync",
-            position = ActionLayout.Position.PANEL
-            )
     @MemberOrder(name = MixinConstants.METADATA_LAYOUT_GROUPNAME, sequence = "800.1")
     public Object act() {
         metaModelService.rebuild(holder.getClass());
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/DomainChangeRecord.java b/api/applib/src/main/java/org/apache/isis/applib/services/DomainChangeRecord.java
new file mode 100644
index 0000000..7cfc48d
--- /dev/null
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/DomainChangeRecord.java
@@ -0,0 +1,155 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.applib.services;
+
+import java.sql.Timestamp;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.Optionality;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.annotation.PropertyLayout;
+import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
+import org.apache.isis.applib.services.message.MessageService;
+import org.apache.isis.applib.services.metamodel.BeanSort;
+import org.apache.isis.applib.services.metamodel.MetaModelService;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
+
+
+/**
+ * An abstraction of some sort of recorded change to a domain object: commands, audit entries or published events.
+ */
+public interface DomainChangeRecord extends HasUniqueId, HasUsername {
+
+    enum ChangeType {
+        COMMAND,
+        AUDIT_ENTRY,
+        PUBLISHED_INTERACTION;
+        @Override
+        public String toString() {
+            return name().replace("_", " ");
+        }
+    }
+
+    /**
+     * Distinguishes commands from audit entries from published events/interactions (when these are shown mixed together in a (standalone) table).
+     */
+    @Property
+    @PropertyLayout(hidden = Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @MemberOrder(name="Identifiers", sequence = "1")
+    ChangeType getType();
+
+
+    /**
+     * The unique identifier (a GUID) of the transaction in which this change occurred.
+     */
+    @Property
+    @MemberOrder(name="Identifiers",sequence = "50")
+    UUID getUniqueId();
+
+
+    /**
+     * The user that caused the change.
+     */
+    @Property
+    @MemberOrder(name="Identifiers", sequence = "10")
+    String getUsername();
+
+
+    /**
+     * The time that the change occurred.
+     */
+    @Property
+    @MemberOrder(name="Identifiers", sequence = "20")
+    Timestamp getTimestamp();
+
+
+    /**
+     * The object type of the domain object being changed.
+     */
+    @Property
+    @PropertyLayout(named="Object Type")
+    @MemberOrder(name="Target", sequence = "10")
+    default String getTargetObjectType() {
+        return getTarget().getObjectType();
+    }
+
+
+
+    /**
+     * The {@link Bookmark} identifying the domain object that has changed.
+     */
+    @Property
+    @PropertyLayout(named="Object")
+    @MemberOrder(name="Target", sequence="30")
+    Bookmark getTarget();
+
+
+    /**
+     * The member interaction (ie action invocation or property edit) which caused the domain object to be changed.
+     *
+     * <p>
+     *     Populated for commands and for published events that represent action invocations or property edits.
+     * </p>
+     */
+    @Property(optionality = Optionality.OPTIONAL)
+    @PropertyLayout(named="Member", hidden = Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @MemberOrder(name="Target", sequence = "20")
+    String getTargetMember();
+
+
+    /**
+     * The value of the property prior to it being changed.
+     *
+     * <p>
+     * Populated only for audit entries.
+     * </p>
+     */
+    @Property(optionality = Optionality.OPTIONAL)
+    @PropertyLayout(hidden = Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @MemberOrder(name="Detail",sequence = "6")
+    String getPreValue();
+
+
+    /**
+     * The value of the property after it has changed.
+     *
+     * <p>
+     * Populated only for audit entries.
+     * </p>
+     */
+    @Property(optionality = Optionality.MANDATORY)
+    @PropertyLayout(hidden = Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @MemberOrder(name="Detail",sequence = "7")
+    String getPostValue();
+
+
+}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/DomainChangeRecord_openTargetObject.java b/api/applib/src/main/java/org/apache/isis/applib/services/DomainChangeRecord_openTargetObject.java
new file mode 100644
index 0000000..7033bb5
--- /dev/null
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/DomainChangeRecord_openTargetObject.java
@@ -0,0 +1,61 @@
+package org.apache.isis.applib.services;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
+import org.apache.isis.applib.services.message.MessageService;
+import org.apache.isis.applib.services.metamodel.BeanSort;
+import org.apache.isis.applib.services.metamodel.MetaModelService;
+
+@Action(
+        semantics = SemanticsOf.SAFE
+        , associateWith = "target"
+        , associateWithSequence = "1"
+)
+@ActionLayout(named = "Open")
+public class DomainChangeRecord_openTargetObject {
+
+    private final DomainChangeRecord domainChangeRecord;
+    public DomainChangeRecord_openTargetObject(DomainChangeRecord domainChangeRecord) {
+        this.domainChangeRecord = domainChangeRecord;
+    }
+
+    @Action(semantics = SemanticsOf.SAFE, associateWith = "target", associateWithSequence = "1")
+    @ActionLayout(named = "Open")
+    public Object openTargetObject() {
+        try {
+            return bookmarkService != null
+                    ? bookmarkService.lookup(domainChangeRecord.getTarget())
+                    : null;
+        } catch(RuntimeException ex) {
+            if(ex.getClass().getName().contains("ObjectNotFoundException")) {
+                messageService.warnUser("Object not found - has it since been deleted?");
+                return null;
+            }
+            throw ex;
+        }
+    }
+
+    public boolean hideOpenTargetObject() {
+        return domainChangeRecord.getTarget() == null;
+    }
+
+    public String disableOpenTargetObject() {
+        final Object targetObject = domainChangeRecord.getTarget();
+        if (targetObject == null) {
+            return null;
+        }
+        final BeanSort sortOfObject = metaModelService.sortOf(domainChangeRecord.getTarget(), MetaModelService.Mode.RELAXED);
+        return !(sortOfObject.isViewModel() || sortOfObject.isEntity())
+                ? "Can only open view models or entities"
+                : null;
+    }
+
+    @Inject BookmarkService bookmarkService;
+    @Inject MessageService messageService;
+    @Inject MetaModelService metaModelService;
+
+}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/HasUsername.java b/api/applib/src/main/java/org/apache/isis/applib/services/HasUsername.java
index 7f7a240..4860b92 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/HasUsername.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/HasUsername.java
@@ -29,6 +29,10 @@ package org.apache.isis.applib.services;
 // tag::refguide[]
 public interface HasUsername {
 
+    /**
+     * The user that created this object.
+     * @return
+     */
     String getUsername();
 
 }
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/TransactionScopeListener.java b/api/applib/src/main/java/org/apache/isis/applib/services/TransactionScopeListener.java
index 4c01d24..028bf40 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/TransactionScopeListener.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/TransactionScopeListener.java
@@ -19,11 +19,14 @@
 
 package org.apache.isis.applib.services;
 
+import org.apache.isis.applib.annotation.IsisInteractionScope;
+
 /**
- * Domain services that need to be aware of transaction boundaries can implement this interface.
+ * Domain services that need to be aware of transaction boundaries can
+ * implement this interface.
  * 
- * @apiNote Implementing services most likely need to be scoped in a way that binds the scope to 
- * the current thread (eg. {@link IsisInteractionScope}) 
+ * @apiNote Implementing services most likely need to be scoped in a way that
+ * binds the scope to the current thread (eg. {@link IsisInteractionScope})
  *  
  * @since 2.0 (renamed from WithTransactionScope)
  */
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/background/BackgroundCommandService.java b/api/applib/src/main/java/org/apache/isis/applib/services/background/BackgroundCommandService.java
deleted file mode 100644
index 4fcf317..0000000
--- a/api/applib/src/main/java/org/apache/isis/applib/services/background/BackgroundCommandService.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.applib.services.background;
-
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.schema.cmd.v2.CommandDto;
-
-/**
- * Persists a {@link org.apache.isis.schema.cmd.v1.CommandDto command-reified} action such that it can be executed asynchronously,
- * for example through a Quartz scheduler.
- *
- * <p>
- * Separate from {@link BackgroundService} primarily so that the default
- * implementation, <tt>BackgroundServiceDefault</tt> (in <tt>isis-module-background</tt>) can
- * delegate to different implementations of this service.
- *
- * <p>
- * There is currently only implementation of this service, <tt>BackgroundCommandServiceJdo</tt> in
- * <tt>o.a.i.module:isis-module-command-jdo</tt>.  That implementation has no UI and no side-effects (the programmatic
- * API is through {@link org.apache.isis.applib.services.background.BackgroundService}).  It is therefore
- * annotated with {@link org.apache.isis.applib.annotation.DomainService} so that it is automatically registered as
- * a service.
- *
- */
-// tag::refguide[]
-public interface BackgroundCommandService extends AutoCloseable {
-
-    void schedule(
-            final CommandDto dto,
-            final Command parentCommand,
-            final String targetClassName,
-            final String targetActionName,
-            final String targetArgs);
-
-    /**
-     * @apiNote refined from AutoCloseable to not throw catched exceptions
-     */
-    @Override
-    default void close() {
-    }
-
-}
-// end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/Bookmark.java b/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/Bookmark.java
index 524fc48..0c4e17b 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/Bookmark.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/Bookmark.java
@@ -73,6 +73,7 @@ public class Bookmark implements Serializable {
 
     /**
      * Round-trip with {@link #toString()} representation.
+     * @return
      */
     // tag::refguide[]
     public static Optional<Bookmark> parse(@Nullable String str) {
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
index f030cb6..5967960 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
@@ -19,200 +19,131 @@
 package org.apache.isis.applib.services.command;
 
 import java.sql.Timestamp;
+import java.util.UUID;
 
-import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.CommandPersistence;
 import org.apache.isis.applib.events.domain.ActionDomainEvent;
 import org.apache.isis.applib.services.HasUniqueId;
-import org.apache.isis.applib.services.background.BackgroundCommandService;
+import org.apache.isis.applib.services.HasUsername;
 import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.wrapper.WrapperFactory;
+import org.apache.isis.applib.services.wrapper.control.AsyncControl;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
+import static org.apache.isis.applib.jaxb.JavaSqlXMLGregorianCalendarMarshalling.toTimestamp;
+
+import lombok.Getter;
+
 /**
  * Represents the <i>intention to</i> invoke either an action or modify a property.  There can be only one such
- * intention per (web) request, so a command is in effect request-scoped.  Note that {@link CommandContext} domain
- * service - from which the current {@link Command} can be obtained - is indeed annotated with
- * {@link javax.enterprise.context.RequestScoped @RequestScoped}.
+ * intention per (web) request, so a command is in effect interaction-scoped.
  *
  * <p>
- * Each Command can be reified into a {@link Command#getMemento() memento} by way of the (internal)
- * <tt>CommandDtoServiceInternal</tt> domain service; typically corresponding to the XML equivalent of a
- * {@link CommandDto} and conforming to the Apache Isis <a href="http://isis.apache.org/schema/cmd/">cmd</a> schema.
+ * Each Command holds a {@link CommandDto} (see Apache Isis <a href="http://isis.apache.org/schema/cmd/">cmd</a> schema)
+ * which reifies all the details in a serializable form.
  * </p>
  *
  * <p>
- *     The {@link Command} interface also captures details of the corresponding action invocation (or property edit),
+ *     It also captures details of the corresponding action invocation (or property edit),
  *     specifically when that action/edit {@link Command#getStartedAt() started} or
  *     {@link Command#getCompletedAt() completed}, and its result, either a {@link Command#getResult() return value}
  *     or an {@link Command#getException() exception}.  Also captures a stack of {@link ActionDomainEvent}s.
  * </p>
  *
  * <p>
- *     Note that when invoking an action, other actions may be invoked courtesy of the {@link WrapperFactory}.  These
- *     "sub-actions" do <i>not</i> modify the contents of the command object; in other words think of the command
+ *     Note that when invoking an action, other actions may be invoked courtesy
+ *     of the {@link WrapperFactory}.  These "sub-actions" do <i>not</i> modify
+ *     the contents of the current command object; in other words think of the command
  *     object as representing the outer-most originating action.
  * </p>
  *
  * <p>
- *     <b>NOTE</b>: in Isis v1.x, one of the responsibilities of {@link Command} was to generate unique sequence numbers for
- *     a given transactionId, where there were three possible sequences that might be generated.
- *     <ul>
- *         <li>
- *         <p>the sequence of changed domain objects being published by the
- *         {@link org.apache.isis.applib.services.publish.PublisherService#publish(Interaction.Execution)}
- *         </p>
- *         <p>
- *         In v2 ... TODO[2158] - what replaces this?
- *         </p>
- *         </li>
- *
- *         <li>
- *         <p>
- *         The sequence of wrapped action invocations (each being published)
- *         </p>
- *         <p>
- *         In v2 this is now done by {@link Interaction#next(String) Interaction} itself.
- *         </p>
- *         </li>
- *
- *         <li>
- *         <p>
- *         and finally, one or more background commands that might be scheduled via the <code>BackgroundService</code>.
- *         </p>
- *         <p>
- *         In v2 ... TODO[2158] - what replaces this?
- *         </p>
- *         </li>
- *     </ul>
- *
+ *     That said, if the sub-action is invoked asynchronously (using
+ *     {@link WrapperFactory#asyncWrap(Object, AsyncControl)} or
+ *     {@link WrapperFactory#asyncWrapMixin(Class, Object, AsyncControl)}), then
+ *     a separate {@link Command} object
+ *     is created, and the originating {@link Command} is set to be its
+ *     {@link Command#getParent() parent}.
  * </p>
- *
  */
 // tag::refguide[]
-public interface Command extends HasUniqueId {
+public class Command implements HasUniqueId, HasUsername {
 
-    // end::refguide[]
-    /**
-     * The user that created the command.
-     */
-    // tag::refguide[]
-    String getUser();                           // <.>
-    // end::refguide[]
+    public Command() {
+        this(UUID.randomUUID());
+    }
+    public Command(final Command parent, final CommandDto commandDto) {
+        this(UUID.fromString(commandDto.getTransactionId()));
+        internal().setCommandDto(commandDto);
+        internal().setParent(parent);
+        internal().setUsername(commandDto.getUser());
+        internal().setTimestamp(toTimestamp(commandDto.getTimestamp()));
+    }
 
-    /**
-     * The date/time at which this command was created.
-     */
-    // tag::refguide[]
-    Timestamp getTimestamp();                   // <.>
-    // end::refguide[]
+    private Command(final UUID uuid) {
+        this.uniqueId = uuid;
+    }
 
-    /**
-     * {@link Bookmark} of the target object (entity or service) on which this action was performed.
-     *
-     * <p>
-     * Will only be populated if a {@link BookmarkService} has been configured.
-     * </p>
-     */
-    // tag::refguide[]
-    Bookmark getTarget();                       // <.>
-    // end::refguide[]
 
-    /**
-     * Holds a string representation of the invoked action, or the edited property, equivalent to
-     * {@link Identifier#toClassAndNameIdentityString()}.
-     */
-    // tag::refguide[]
-    String getMemberIdentifier();               // <.>
-    // end::refguide[]
+    @Getter
+    private UUID uniqueId;
 
+    // end::refguide[]
     /**
-     * A human-friendly description of the class of the target object.
+     * The user that created the command.
      */
     // tag::refguide[]
-    String getTargetClass();                    // <.>
+    @Getter
+    private String username;                    // <.>
     // end::refguide[]
 
     /**
-     * The human-friendly name of the action invoked/property edited on the target object.
+     * The date/time at which this command was created.
      */
     // tag::refguide[]
-    String getTargetAction();                   // <.>
+    @Getter
+    private Timestamp timestamp;                // <.>
     // end::refguide[]
 
     /**
-     * A human-friendly description of the arguments with which the action was invoked.
+     * Serializable representation of the action invocation/property edit.
      */
     // tag::refguide[]
-    String getArguments();                      // <.>
+    @Getter
+    private CommandDto commandDto;              // <.>
     // end::refguide[]
 
     /**
-     *
-     * A formal (XML or similar) specification of the action to invoke/being invoked.
+     * Also available in {@link #getCommandDto()}, is the {@link Bookmark} of
+     * the target object (entity or service) on which this action/edit was performed.
      */
     // tag::refguide[]
-    String getMemento();                        // <.>
+    @Getter
+    private Bookmark target;                    // <.>
     // end::refguide[]
 
     /**
-     *
-     * The mechanism by which this command is to be executed, either synchronously &quot;in the
-     * {@link CommandExecuteIn#FOREGROUND foreground}&quot; or is to be executed asynchronously &quot;in the
-     * {@link CommandExecuteIn#BACKGROUND background}&quot; through the {@link BackgroundCommandService}.
+     * Also available in {@link #getCommandDto()}, holds a string
+     * representation of the invoked action, or the edited property.
      */
     // tag::refguide[]
-    CommandExecuteIn getExecuteIn();            // <.>
+    @Getter
+    private String logicalMemberIdentifier;     // <.>
     // end::refguide[]
 
-    // tag::refguide2[]
-    enum Executor {
-        // end::refguide2[]
-        /**
-         * Command being executed by the end-user.
-         */
-        // tag::refguide2[]
-        USER,
-        // end::refguide2[]
-        /**
-         * Command being executed by a background execution service.
-         */
-        // tag::refguide2[]
-        BACKGROUND,
-        // end::refguide2[]
-        /**
-         * Command being executed for some other reason, eg as result of redirect-after-post, or the homePage action.
-         */
-        // tag::refguide2[]
-        OTHER
-    }
-    // end::refguide2[]
-
     /**
-     * The (current) executor of this command.
-     *
-     * <p>
-     * Note that (even for implementations of {@link BackgroundCommandService} that persist {@link Command}s), this
-     * property is never (likely to be) persisted, because it is always updated to indicate how the command is
-     * currently being executed.
+     * For commands created through the {@link WrapperFactory} (using
+     * {@link WrapperFactory#asyncWrap(Object, AsyncControl)} or
+     * {@link WrapperFactory#asyncWrapMixin(Class, Object, AsyncControl)}),
+     * captures the parent command.
      *
      * <p>
-     * If the {@link #getExecutor() executor} matches the required {@link #getExecuteIn() execution policy}, then the
-     * command actually is executed.  The combinations are:
-     * <ul>
-     * <li>executor = USER, executeIn = FOREGROUND, then execute</li>
-     * <li>executor = USER, executeIn = BACKGROUND, then persist and return persisted command as a placeholder for the result</li>
-     * <li>executor = BACKGROUND, executeIn = FOREGROUND, then ignore</li>
-     * <li>executor = BACKGROUND, executeIn = BACKGROUND, then execute, update the command with result</li>
-     * </ul>
-     *
+     *     Will return <code>null</code> if there is no parent.
+     * </p>
      */
     // tag::refguide[]
-    Executor getExecutor();                     // <.>
+    @Getter
+    private Command parent;                     // <.>
     // end::refguide[]
 
     /**
@@ -229,7 +160,8 @@ public interface Command extends HasUniqueId {
      * {@link Interaction.Execution#getStartedAt()}.
      */
     // tag::refguide[]
-    Timestamp getStartedAt();                   // <.>
+    @Getter
+    private Timestamp startedAt;                // <.>
     // end::refguide[]
 
     /**
@@ -246,224 +178,170 @@ public interface Command extends HasUniqueId {
      * {@link Interaction.Execution#getCompletedAt()}.
      */
     // tag::refguide[]
-    Timestamp getCompletedAt();                 // <.>
-    // end::refguide[]
-
-    /**
-     * For actions created through the {@link BackgroundService} and {@link BackgroundCommandService},
-     * captures the parent action.
-     */
-    // tag::refguide[]
-    Command getParent();                        // <.>
+    @Getter
+    private Timestamp completedAt;              // <.>
     // end::refguide[]
 
     /**
-     * For an command that has actually been executed, holds the exception stack
-     * trace if the action invocation/property modification threw an exception.
+     * For a command that has actually been executed, holds a {@link Bookmark}
+     * to the object returned by the corresponding action/property modification.
      *
      * <p>
-     *     Previously this field was deprecated (on the basis that the exception is also held in
-     *     {@link Interaction.Execution#getThrew()}). However, this property is now used in master/slave
-     *     replay scenarios which may query a persisted Command.
+     *     This property is used in replay scenarios to verify the outcome of
+     *     the replayed command, eg for regression testing.
      * </p>
      *
-     * See also {@link Interaction#getCurrentExecution()} and  {@link org.apache.isis.applib.services.iactn.Interaction.Execution#getThrew()}.
+     * See also  {@link Interaction#getCurrentExecution()} and
+     * {@link org.apache.isis.applib.services.iactn.Interaction.Execution#getReturned()}.
      */
     // tag::refguide[]
-    String getException();                      // <.>
+    @Getter
+    private Bookmark result;                    // <.>
     // end::refguide[]
 
     /**
-     * For an command that has actually been executed, holds a {@link Bookmark} to the object returned by the corresponding action/property modification.
+     * For a command that has actually been executed, holds the exception stack
+     * trace if the action invocation/property modification threw an exception.
      *
      * <p>
-     *     Previously this field was deprecated (on the basis that the returned value is also held in
-     *     {@link Interaction.Execution#getReturned()}). However, this property is now used in master/slave
-     *     replay scenarios which may query a persisted Command.
+     *     This property is used in replay scenarios to verify the outcome of
+     *     the replayed command, eg for regression testing.
      * </p>
      *
-     * See also  {@link Interaction#getCurrentExecution()} and  {@link org.apache.isis.applib.services.iactn.Interaction.Execution#getReturned()}.
+     * See also {@link Interaction#getCurrentExecution()} and
+     * {@link org.apache.isis.applib.services.iactn.Interaction.Execution#getThrew()}.
      */
     // tag::refguide[]
-    Bookmark getResult();                       // <.>
+    @Getter
+    private Throwable exception;                    // <.>
     // end::refguide[]
 
     /**
-     * Whether this command should ultimately be persisted (if the configured {@link BackgroundCommandService} supports
-     * it) or not.
+     * Whether this command resulted in a change of state to the system.
      *
      * <p>
-     * If the action to be executed has been annotated with the {@link Action#command()} attribute
-     * then (unless its {@link Action#commandPersistence()} persistence} attribute has been set to a different value
-     * than its default of {@link org.apache.isis.applib.annotation.CommandPersistence#PERSISTED persisted}), the
-     * {@link Command} object will be persisted.
-     *
-     * <p>
-     * However, it is possible to prevent the {@link Command} object from ever being persisted by setting the
-     * {@link org.apache.isis.applib.annotation.Action#commandPersistence() persistence} attribute to
-     * {@link org.apache.isis.applib.annotation.CommandPersistence#NOT_PERSISTED}, or it can be set to
-     * {@link org.apache.isis.applib.annotation.CommandPersistence#IF_HINTED}, meaning it is dependent
-     * on whether {@link #setPersistHint(boolean) a hint has been set} by some other means.
+     *     This can be used as a hint to decide whether to persist the command
+     *     to a datastore, for example for auditing (though
+     *     {@link org.apache.isis.applib.services.publish.PublisherService} is
+     *     an alternative for that use case) or so that it can be retrieved
+     *     and replayed on another system, eg for regression testing.
+     * </p>
      *
-     * <p>
-     * For example, a {@link BackgroundCommandService} implementation that creates persisted background commands ought
-     * associate them (via its {@link Command#getParent() parent}) to an original persisted
-     * {@link Command}.  The hinting mechanism allows the service to suggest that the parent command be persisted so
-     * that the app can then provide a mechanism to find all child background commands for that original parent command.
      */
     // tag::refguide[]
-    CommandPersistence getPersistence();        // <.>
+    @Getter
+    private boolean systemStateChanged;                // <.>
     // end::refguide[]
 
-    /**
-     * Whether that this {@link Command} should be persisted, if possible.
-     */
-    // tag::refguide[]
-    boolean isPersistHint();                    // <.>
-    // end::refguide[]
 
-    /**
-     * <b>NOT API</b>: intended to be called only by the framework.
-     */
-    public static interface Internal {
+    private final Command.Internal INTERNAL = new Internal();
 
+    public class Internal {
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
          * Implementation notes: set when the Isis PersistenceSession is opened.
          */
-        void setUser(String user);
-
+        public void setUsername(String username) {
+            Command.this.username = username;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
          * Implementation notes: set when the Isis PersistenceSession is opened.
          */
-        void setTimestamp(Timestamp timestamp);
-
+        public void setTimestamp(Timestamp timestamp) {
+            Command.this.timestamp = timestamp;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
-         * Implementation notes: set when the action is invoked (in the ActionInvocationFacet).
+         *     Only populated for async commands created through the
+         *     {@link WrapperFactory}.
+         * </p>
          */
-        void setTarget(Bookmark target);
-
+        public void setParent(Command parent) {
+            Command.this.parent = parent;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
-         * Implementation notes: set when the action is invoked (in <tt>ActionInvocationFacet</tt>) or in
-         * property edited (in <tt>PropertySetterFacet</tt>).
+         * Implementation notes: set when the action is invoked (in the <tt>ActionInvocationFacet</tt>).
+         * @param commandDto
          */
-        void setMemberIdentifier(String memberIdentifier);
-
+        public void setCommandDto(CommandDto commandDto) {
+            Command.this.commandDto = commandDto;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
-         * Implementation notes: set when the action is invoked (in the <tt>ActionInvocationFacet</tt>) or property edited
-         * (in the <tt>PropertySetterOrClearFacet</tt>).
+         * Implementation notes: set when the action is invoked (in the ActionInvocationFacet).
          */
-        void setTargetAction(String targetAction);
-
-
+        public void setTarget(Bookmark target) {
+            Command.this.target = target;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
-         * Implementation notes: set when the action is invoked (in the <tt>ActionInvocationFacet</tt>).
+         * Implementation notes: set when the action is invoked (in
+         * <tt>ActionInvocationFacet</tt>) or property is edited (in
+         * <tt>PropertySetterFacet</tt>).
          */
-        void setArguments(final String arguments);
-
+        public void setLogicalMemberIdentifier(String logicalMemberIdentifier) {
+            Command.this.logicalMemberIdentifier = logicalMemberIdentifier;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          */
-        void setExecutor(final Executor executor);
-
+        public void setStartedAt(Timestamp startedAt) {
+            Command.this.startedAt = startedAt;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          */
-        void setResult(Bookmark resultBookmark);
-
+        public void setCompletedAt(final Timestamp completed) {
+            Command.this.completedAt = completed;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          */
-        void setException(String stackTrace);
-
+        public void setResult(final Bookmark result) {
+            Command.this.result = result;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          */
-        void setParent(final Command parent);
-
+        public void setException(final Throwable exception) {
+            Command.this.exception = exception;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
-         *     Previously this field was deprecated (on the basis that the completedAt is also held in
-         *     {@link Interaction.Execution#getCompletedAt()}). However, this property is now used in master/slave
-         *     replay scenarios which may query a persisted Command.
+         * Hint that this {@link Command} has resulted in a change of state to the system.
+         * Implementations can use this to persist the command, for example.
          * </p>
-         *
-         * See also {@link Interaction#getCurrentExecution()} and
-         * {@link Interaction.Execution#setCompletedAt(Timestamp)}.
          */
-        void setCompletedAt(Timestamp completedAt);
-
-        /**
-         * <b>NOT API</b>: intended to be called only by the framework.
-         *
-         *
-         * <p>
-         *     Previously this field was deprecated (on the basis that the completedAt is also held in
-         *     {@link Interaction.Execution#getCompletedAt()}). However, this property is now used in master/slave
-         *     replay scenarios which may query a persisted Command.
-         * </p>
-         *
-         * See also {@link Interaction#getCurrentExecution()} and
-         * {@link #setStartedAt(org.apache.isis.applib.services.clock.ClockService, org.apache.isis.applib.services.metrics.MetricsService)}.
-         */
-        void setStartedAt(Timestamp startedAt);
-
-        /**
-         * <b>NOT API</b>: intended to be called only by the framework.
-         *
-         * <p>
-         * Implementation notes: set when the action is invoked (in the <tt>ActionInvocationFacet</tt>).
-         */
-        void setMemento(final String memento);
-
-        /**
-         * <b>NOT API</b>: intended to be called only by the framework.
-         *
-         * <p>
-         * Implementation notes: set when the action is invoked (in the <tt>ActionInvocationFacet</t>).
-         */
-        void setTargetClass(String targetClass);
-
-        /**
-         * <b>NOT API</b>: intended to be called only by the framework.
-         */
-        void setPersistence(final CommandPersistence persistence);
-
-        /**
-         * Hint that this {@link Command} should be persisted, if possible.
-         *
-         * <p>
-         * <b>NOT API</b>: intended to be called only by the framework.
-         *
-         * @see #getPersistence()
-         */
-        void setPersistHint(boolean persistHint);
-    }
+        public void setSystemStateChanged(boolean systemStateChanged) {
+            Command.this.systemStateChanged = systemStateChanged;
+        }
+    };
 
     /**
      * <b>NOT API</b>: intended to be called only by the framework.
      */
-    Internal internal();
+    public Command.Internal internal() {
+        return INTERNAL;
+    }
+
 
 // tag::refguide[]
+
 }
 // end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandContext.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandContext.java
index 4d07f9d..dea7b9a 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandContext.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandContext.java
@@ -23,6 +23,7 @@ import java.util.Optional;
 import javax.inject.Inject;
 import javax.inject.Named;
 
+import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Primary;
 import org.springframework.core.annotation.Order;
@@ -30,8 +31,10 @@ import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.IsisInteractionScope;
 import org.apache.isis.applib.annotation.OrderPrecedence;
-import org.apache.isis.applib.services.command.Command.Executor;
+import org.apache.isis.applib.services.TransactionScopeListener;
 import org.apache.isis.applib.services.inject.ServiceInjector;
+import org.apache.isis.applib.services.metrics.MetricsService;
+import org.apache.isis.applib.services.registry.ServiceRegistry;
 
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
@@ -46,16 +49,17 @@ import lombok.RequiredArgsConstructor;
 // tag::refguide[]
 @Service
 @Named("isisApplib.CommandContext")
-@Order(OrderPrecedence.MIDPOINT)
+@Order(OrderPrecedence.EARLY - 10) // before ChangedObjectService
 @Primary
 @Qualifier("Default")
 @IsisInteractionScope
 @RequiredArgsConstructor(onConstructor_ = {@Inject})
 //@Log4j2
-public class CommandContext {
+public class CommandContext implements TransactionScopeListener, DisposableBean {
 
     private final ServiceInjector serviceInjector;
-    
+    private final MetricsService metricsService;
+
     @Getter
     private Command command;
 
@@ -70,9 +74,16 @@ public class CommandContext {
         }
     }
 
-    public Optional<Executor> getCurrentExecutor() {
-        return Optional.ofNullable(getCommand())
-                .map(Command::getExecutor);
+    @Override
+    public void destroy() throws Exception {
+        setCommand(null);
+    }
+
+    @Override
+    public void onTransactionEnded() {
+        getCommand().internal().setSystemStateChanged(
+                getCommand().isSystemStateChanged() ||
+                metricsService.numberObjectsDirtied() > 0);
     }
 
     // tag::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDefault.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDefault.java
deleted file mode 100644
index 069acd4..0000000
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDefault.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.applib.services.command;
-
-import java.sql.Timestamp;
-import java.util.UUID;
-
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.CommandPersistence;
-import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.applib.util.ObjectContracts;
-import org.apache.isis.applib.util.ToString;
-
-import lombok.Getter;
-
-public class CommandDefault implements Command {
-
-    public CommandDefault() {
-        this.executor = Executor.OTHER;
-        this.uniqueId = UUID.randomUUID();
-    }
-
-    @Getter
-    private String memberIdentifier;
-
-    @Getter
-    private String targetClass;
-
-    @Getter
-    private String targetAction;
-
-    @Getter
-    private String arguments;
-
-    @Getter
-    private String memento;
-
-    @Getter
-    private Bookmark target;
-
-    @Getter
-    private Timestamp timestamp;
-
-    @Getter
-    private Timestamp startedAt;
-
-    @Getter
-    private Timestamp completedAt;
-
-    @Getter
-    private String user;
-
-    @Getter
-    private Executor executor;
-
-    @Getter
-    private CommandExecuteIn executeIn;
-
-    @Getter
-    private Command parent;
-
-    @Getter
-    private Bookmark result;
-
-    @Getter
-    private String exception;
-
-    @Getter
-    private UUID uniqueId;
-
-    @Getter
-    private CommandPersistence persistence;
-
-    @Getter
-    private boolean persistHint;
-
-    // -- toString
-
-    private static final ToString<CommandDefault> toString = ObjectContracts
-            .toString("startedAt", CommandDefault::getStartedAt)
-            .thenToString("user", CommandDefault::getUser)
-            .thenToString("memberIdentifier", CommandDefault::getMemberIdentifier)
-            .thenToString("target", CommandDefault::getTarget)
-            .thenToString("transactionId", CommandDefault::getUniqueId);
-
-    @Override
-    public String toString() {
-        return toString.toString(this);
-    }
-
-
-    // -- FRAMEWORK INTERNAL
-
-    private final Command.Internal INTERNAL = new Command.Internal() {
-        @Override
-        public void setMemberIdentifier(String actionIdentifier) {
-            CommandDefault.this.memberIdentifier = actionIdentifier;
-        }
-        @Override
-        public void setTargetClass(String targetClass) {
-            CommandDefault.this.targetClass = targetClass;
-        }
-        @Override
-        public void setTargetAction(String targetAction) {
-            CommandDefault.this.targetAction = targetAction;
-        }
-        @Override
-        public void setArguments(String arguments) {
-            CommandDefault.this.arguments = arguments;
-        }
-        @Override
-        public void setMemento(String memento) {
-            CommandDefault.this.memento = memento;
-        }
-        @Override
-        public void setTarget(Bookmark target) {
-            CommandDefault.this.target = target;
-        }
-        @Override
-        public void setTimestamp(Timestamp timestamp) {
-            CommandDefault.this.timestamp = timestamp;
-        }
-        @Override
-        public void setStartedAt(Timestamp startedAt) {
-            CommandDefault.this.startedAt = startedAt;
-        }
-        @Override
-        public void setCompletedAt(final Timestamp completed) {
-            CommandDefault.this.completedAt = completed;
-        }
-        @Override
-        public void setUser(String user) {
-            CommandDefault.this.user = user;
-        }
-        @Override
-        public void setParent(Command parent) {
-            CommandDefault.this.parent = parent;
-        }
-        @Override
-        public void setResult(final Bookmark result) {
-            CommandDefault.this.result = result;
-        }
-        @Override
-        public void setException(final String exceptionStackTrace) {
-            CommandDefault.this.exception = exceptionStackTrace;
-        }
-        @Override
-        public void setPersistence(CommandPersistence persistence) {
-            CommandDefault.this.persistence = persistence;
-        }
-        @Override
-        public void setPersistHint(boolean persistHint) {
-            CommandDefault.this.persistHint = persistHint;
-        }
-        @Override
-        public void setExecutor(Executor executor) {
-            CommandDefault.this.executor = executor;
-        }
-    };
-
-    @Override
-    public Command.Internal internal() {
-        return INTERNAL;
-    }
-
-}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDtoProcessor.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDtoProcessor.java
index 3c7336e..60edc81 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDtoProcessor.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDtoProcessor.java
@@ -18,7 +18,6 @@
  */
 package org.apache.isis.applib.services.command;
 
-import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
 // tag::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDtoProcessorForActionAbstract.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDtoProcessorForActionAbstract.java
index 531c945..97c9780 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDtoProcessorForActionAbstract.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDtoProcessorForActionAbstract.java
@@ -27,8 +27,8 @@ import org.apache.isis.schema.cmd.v2.ParamsDto;
  * Convenience adapter for command processors for action invocations.
  */
 public abstract class CommandDtoProcessorForActionAbstract implements CommandDtoProcessor {
-    protected CommandDto asDto(final CommandWithDto commandWithDto) {
-        return commandWithDto.asDto();
+    protected CommandDto asDto(final Command command) {
+        return command.getCommandDto();
     }
     protected ActionDto getActionDto(final CommandDto commandDto) {
         return (ActionDto) commandDto.getMember();
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDtoProcessorForPropertyAbstract.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDtoProcessorForPropertyAbstract.java
index 6bc4d69..b8e2dd3 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDtoProcessorForPropertyAbstract.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDtoProcessorForPropertyAbstract.java
@@ -26,8 +26,8 @@ import org.apache.isis.schema.cmd.v2.PropertyDto;
  */
 public abstract class CommandDtoProcessorForPropertyAbstract
 implements CommandDtoProcessor {
-    protected CommandDto asDto(final CommandWithDto commandWithDto) {
-        return commandWithDto.asDto();
+    protected CommandDto asDto(final Command commandWithDto) {
+        return commandWithDto.getCommandDto();
     }
     protected PropertyDto getPropertyDto(final CommandDto commandDto) {
         return (PropertyDto) commandDto.getMember();
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandExecutorService.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandExecutorService.java
index 56d029b..4634dc5 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandExecutorService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandExecutorService.java
@@ -48,13 +48,22 @@ public interface CommandExecutorService {
      * Executes the specified command.
      *
      * @param sudoPolicy
-     * @param commandWithDto
+     * @param command
      * @return - any exception raised by the command.
      */
     // tag::refguide[]
-    void executeCommand(
+    Bookmark executeCommand(
+            SudoPolicy sudoPolicy,          // <.>
+            Command command                 // <.>
+    );
+
+    Bookmark executeCommand(
             SudoPolicy sudoPolicy,          // <.>
-            CommandWithDto commandWithDto   // <.>
+            CommandDto commandDto           // <.>
+    );
+
+    Bookmark executeCommand(
+            Command command                 // <.>
     );
 
     Bookmark executeCommand(
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandService.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandService.java
new file mode 100644
index 0000000..ce19893
--- /dev/null
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandService.java
@@ -0,0 +1,92 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.applib.services.command;
+
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Primary;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Service;
+
+import org.apache.isis.applib.annotation.IsisInteractionScope;
+import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.command.spi.CommandServiceListener;
+
+import lombok.extern.log4j.Log4j2;
+
+@Service
+@Named("isisApplib.CommandService")
+@Order(OrderPrecedence.MIDPOINT)
+@Primary
+@Qualifier("Default")
+@Log4j2
+// tag::refguide[]
+public class CommandService {
+
+    // end::refguide[]
+    /**
+     * Simply instantiates the appropriate instance of the {@link Command}.
+     *
+     * <p>
+     * Its members will be populated automatically by the framework (the
+     * {@link Command}'s {@link Command#getTimestamp()},
+     * {@link Command#getUsername()} and {@link Command#getUniqueId()}).
+     * </p>
+     */
+    // tag::refguide[]
+    public Command create() {                   // <.>
+        return new Command();
+    }
+
+    // end::refguide[]
+
+    /**
+     * &quot;Complete&quot; the command, providing an opportunity ot persist
+     * a memento of the command if the
+     * {@link Command#isSystemStateChanged() system state has changed}.
+     *
+     * <p>
+     *     The framework will automatically have set the {@link Command#getCompletedAt()} property.
+     * </p>
+     */
+    // tag::refguide[]
+    public void complete(final Command command) {   // <.>
+        // ...
+    // end::refguide[]
+
+        if(command.getLogicalMemberIdentifier() == null) {
+            // eg if seed fixtures
+            return;
+        }
+
+        log.debug("complete: {}, systemStateChanged {}", command.getLogicalMemberIdentifier(), command.isSystemStateChanged());
+
+    // tag::refguide[]
+        commandServiceListeners.forEach(x -> x.onComplete(command));
+    }
+
+    @Inject List<CommandServiceListener> commandServiceListeners;
+
+}
+// end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandWithDto.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandWithDto.java
deleted file mode 100644
index cd421ea..0000000
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandWithDto.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.applib.services.command;
-
-import org.apache.isis.applib.annotation.Programmatic;
-import org.apache.isis.schema.cmd.v2.CommandDto;
-
-// tag::refguide[]
-public interface CommandWithDto extends Command {
-
-    String USERDATA_KEY_TARGET_CLASS = "targetClass";
-    String USERDATA_KEY_TARGET_ACTION = "targetAction";
-    String USERDATA_KEY_ARGUMENTS = "arguments";
-    String USERDATA_KEY_RETURN_VALUE = "returnValue";
-    String USERDATA_KEY_EXCEPTION = "exception";
-
-    CommandDto asDto();
-}
-// end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
deleted file mode 100644
index eb3abce..0000000
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.applib.services.command.spi;
-
-import org.apache.isis.applib.services.command.Command;
-
-/**
- * Default factory service for {@link Command}s.
- */
-// tag::refguide[]
-public interface CommandService {
-
-    // end::refguide[]
-    /**
-     * Simply instantiates the appropriate instance of the {@link Command}.
-     *
-     * <p>
-     * Its members will be populated automatically by the framework (the {@link Command}'s
-     * {@link Command#getTimestamp()}, {@link Command#getUser()} and {@link Command#getUniqueId()}).
-     * </p>
-     */
-    // tag::refguide[]
-    Command create();                               // <.>
-    // end::refguide[]
-
-    /**
-     * Hint for this implementation to eagerly persist the {@link Command}s if possible; influences the behaviour
-     * of actions annotated to execute in the {@link org.apache.isis.applib.annotation.CommandExecuteIn#BACKGROUND}.
-     */
-    // tag::refguide[]
-    boolean persistIfPossible(Command command);     // <.>
-    // end::refguide[]
-
-    /**
-     * &quot;Complete&quot; the command, typically meaning to indicate that the command is completed, and to
-     * persist it if its {@link Command#getPersistence()} and {@link Command#isPersistHint() persistence hint}
-     * indicate that it should be.
-     *
-     * <p>
-     * However, not every implementation necessarily {@link #persistIfPossible(Command) supports persistence}.
-     *
-     * <p>
-     *     The framework will automatically have set the {@link Command#getCompletedAt()} property.
-     * </p>
-     */
-    // tag::refguide[]
-    void complete(final Command command);           // <.>
-}
-// end::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/HasUsername.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandServiceListener.java
similarity index 64%
copy from api/applib/src/main/adoc/modules/applib-svc/examples/services/HasUsername.java
copy to api/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandServiceListener.java
index 7f7a240..5d10793 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/HasUsername.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandServiceListener.java
@@ -16,20 +16,25 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.applib.services;
+package org.apache.isis.applib.services.command.spi;
+
+import org.apache.isis.applib.services.command.Command;
 
 /**
- * Mix-in interface for objects (usually created by service implementations) that are be persistable,
- * and so can be associated with a username, usually of the user that has performed some operation.
- *
- * <p>
- * Other services can then use this username as a means to contributed actions/collections to render such additional
- * information relating to the activities of the user.
+ * SPI
  */
 // tag::refguide[]
-public interface HasUsername {
-
-    String getUsername();
+public interface CommandServiceListener {
 
+    /**
+     * Notifies that the command has completed.
+     *
+     * <p>
+     *     This is an opportunity for implementations to process the command,
+     *     for example to persist a representation of it.
+     * </p>
+     */
+    // tag::refguide[]
+    void onComplete(final Command command);           // <.>
 }
 // end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/conmap/command/ContentMappingServiceForCommandDto.java b/api/applib/src/main/java/org/apache/isis/applib/services/conmap/command/ContentMappingServiceForCommandDto.java
index 480cb7b..c4579c4 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/conmap/command/ContentMappingServiceForCommandDto.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/conmap/command/ContentMappingServiceForCommandDto.java
@@ -20,6 +20,7 @@ package org.apache.isis.applib.services.conmap.command;
 
 import java.sql.Timestamp;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -35,11 +36,11 @@ import org.apache.isis.applib.jaxb.JavaSqlXMLGregorianCalendarMarshalling;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandDtoProcessor;
-import org.apache.isis.applib.services.command.CommandWithDto;
 import org.apache.isis.applib.services.conmap.ContentMappingService;
 import org.apache.isis.applib.services.conmap.command.spi.CommandDtoProcessorService;
 import org.apache.isis.applib.services.metamodel.MetaModelService;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
+import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.common.v2.PeriodDto;
 
@@ -63,27 +64,27 @@ public class ContentMappingServiceForCommandDto implements ContentMappingService
     /**
      * Not part of the {@link ContentMappingService} API.
      */
-    public CommandDto map(final CommandWithDto commandWithDto) {
-        return asProcessedDto(commandWithDto);
+    public CommandDto map(final Command command) {
+        return asProcessedDto(command);
     }
 
     CommandDto asProcessedDto(final Object object) {
-        if (!(object instanceof CommandWithDto)) {
+        if (!(object instanceof Command)) {
             return null;
         }
-        final CommandWithDto commandWithDto = (CommandWithDto) object;
-        return asProcessedDto(commandWithDto);
+        final Command command = (Command) object;
+        return asProcessedDto(command);
     }
 
-    private CommandDto asProcessedDto(final CommandWithDto commandWithDto) {
-        if(commandWithDto == null) {
+    private CommandDto asProcessedDto(final Command command) {
+        if(command == null) {
             return null;
         }
-        CommandDto commandDto = commandWithDto.asDto();
+        CommandDto commandDto = command.getCommandDto();
 
         // global processors
         for (final CommandDtoProcessorService commandDtoProcessorService : commandDtoProcessorServices) {
-            commandDto = commandDtoProcessorService.process(commandWithDto, commandDto);
+            commandDto = commandDtoProcessorService.process(command, commandDto);
             if(commandDto == null) {
                 // any processor could return null, effectively breaking the chain.
                 return null;
@@ -96,7 +97,7 @@ public class ContentMappingServiceForCommandDto implements ContentMappingService
         if (commandDtoProcessor == null) {
             return commandDto;
         }
-        return commandDtoProcessor.process(commandWithDto, commandDto);
+        return commandDtoProcessor.process(command, commandDto);
     }
 
 
@@ -115,7 +116,7 @@ public class ContentMappingServiceForCommandDto implements ContentMappingService
         public CommandDto process(final Command command, CommandDto commandDto) {
 
             // for some reason this isn't being persisted initially, so patch it in.  TODO: should fix this
-            commandDto.setUser(command.getUser());
+            commandDto.setUser(command.getUsername());
 
             // the timestamp field was only introduced in v1.4 of cmd.xsd, so there's no guarantee
             // it will have been populated.  We therefore copy the value in from CommandWithDto entity.
@@ -124,20 +125,15 @@ public class ContentMappingServiceForCommandDto implements ContentMappingService
                 commandDto.setTimestamp(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(timestamp));
             }
 
-            CommandDtoUtils.setUserData(commandDto,
-                    CommandWithDto.USERDATA_KEY_TARGET_CLASS, command.getTargetClass());
-            CommandDtoUtils.setUserData(commandDto,
-                    CommandWithDto.USERDATA_KEY_TARGET_ACTION, command.getTargetAction());
-            CommandDtoUtils.setUserData(commandDto,
-                    CommandWithDto.USERDATA_KEY_ARGUMENTS, command.getArguments());
-
             final Bookmark result = command.getResult();
             CommandDtoUtils.setUserData(commandDto,
-                    CommandWithDto.USERDATA_KEY_RETURN_VALUE, result != null ? result.toString() : null);
+                    UserDataKeys.RESULT, result != null ? result.toString() : null);
             // knowing whether there was an exception is on the master is used to determine whether to
             // continue when replayed on the slave if an exception occurs there also
+            Throwable exception = command.getException();
             CommandDtoUtils.setUserData(commandDto,
-                    CommandWithDto.USERDATA_KEY_EXCEPTION, command.getException());
+                    UserDataKeys.EXCEPTION,
+                        _Exceptions.asStacktrace(exception));
 
             PeriodDto timings = CommandDtoUtils.timingsFor(commandDto);
             timings.setStartedAt(JavaSqlXMLGregorianCalendarMarshalling.toXMLGregorianCalendar(command.getStartedAt()));
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/background/package-info.java b/api/applib/src/main/java/org/apache/isis/applib/services/conmap/command/UserDataKeys.java
similarity index 65%
rename from api/applib/src/main/adoc/modules/applib-svc/examples/services/background/package-info.java
rename to api/applib/src/main/java/org/apache/isis/applib/services/conmap/command/UserDataKeys.java
index f63812d..bc1bb2f 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/background/package-info.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/conmap/command/UserDataKeys.java
@@ -16,12 +16,19 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
+package org.apache.isis.applib.services.conmap.command;
+
+import org.apache.isis.schema.cmd.v2.CommandDto;
+
+import lombok.experimental.UtilityClass;
 
 /**
- * The {@link org.apache.isis.applib.services.background.BackgroundService2} domain service, and also the companion
- * {@link org.apache.isis.applib.services.background.BackgroundCommandService2} SPI service, enable commands to be
- * persisted such that they may be invoked in the background
- *
- *
+ * Keys used in {@link CommandDto#getUserData()} to marshall the command's results
  */
-package org.apache.isis.applib.services.background;
\ No newline at end of file
+@UtilityClass
+public class UserDataKeys {
+
+    public static String RESULT = UserDataKeys.class.getName() + "#" + "RESULT";
+    public static String EXCEPTION = UserDataKeys.class.getName() + "#" + "EXCEPTION";
+
+}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCache.java b/api/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCache.java
index 6e22285..c0e6a75 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCache.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCache.java
@@ -21,6 +21,8 @@ package org.apache.isis.applib.services.queryresultscache;
 import java.util.Arrays;
 import java.util.concurrent.Callable;
 
+import org.springframework.beans.factory.DisposableBean;
+
 import org.apache.isis.applib.services.MethodReferences;
 
 import lombok.Data;
@@ -38,7 +40,7 @@ import lombok.Getter;
  * available for use; no further configuration is required.
  */
 // tag::refguide[]
-public interface QueryResultsCache {
+public interface QueryResultsCache extends DisposableBean {
 
     <T> T execute(                                      // <.>
             Callable<T> callable,
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/scratchpad/Scratchpad.java b/api/applib/src/main/java/org/apache/isis/applib/services/scratchpad/Scratchpad.java
index 46553f9..3be13cd 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/scratchpad/Scratchpad.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/scratchpad/Scratchpad.java
@@ -24,6 +24,7 @@ import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 import javax.inject.Named;
 
+import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Primary;
 import org.springframework.core.annotation.Order;
@@ -46,7 +47,8 @@ import lombok.extern.log4j.Log4j2;
  * available for use; no further configuration is required.
  */
 // tag::refguide[]
-public interface Scratchpad {
+public interface Scratchpad
+        extends DisposableBean {
 
     // end::refguide[]
     /**
@@ -62,12 +64,6 @@ public interface Scratchpad {
     // tag::refguide[]
     public void put(Object key, Object value);
 
-    // end::refguide[]
-    /**
-     * Clear any user data.
-     */
-    // tag::refguide[]
-    public void clear();
 
 }
 // end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/sudo/SudoService.java b/api/applib/src/main/java/org/apache/isis/applib/services/sudo/SudoService.java
index f5e94e2..621828b 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/sudo/SudoService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/sudo/SudoService.java
@@ -20,9 +20,8 @@
 package org.apache.isis.applib.services.sudo;
 
 import java.util.List;
-import java.util.concurrent.Callable;
+import java.util.function.Supplier;
 
-import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.services.user.UserService;
 
 /**
@@ -65,7 +64,7 @@ public interface SudoService {
     // tag::refguide[]
     <T> T sudo(                                             // <.>
             String username,
-            final Callable<T> callable);
+            final Supplier<T> supplier);
 
     // end::refguide[]
     /**
@@ -83,7 +82,7 @@ public interface SudoService {
     // tag::refguide[]
     <T> T sudo(                                             // <.>
             String username, List<String> roles,
-            final Callable<T> callable);
+            final Supplier<T> supplier);
 
     // end::refguide[]
 
@@ -96,7 +95,7 @@ public interface SudoService {
         // end::refguide-1[]
         /**
          * Any implementation of the {@link SudoService} should call this method on all implementations of the
-         * {@link Spi} service whenever {@link SudoService#sudo(String, List, Callable)} (or its overloads)
+         * {@link Spi} service whenever {@link SudoService#sudo(String, List, Supplier)} (or its overloads)
          * is called.
          *
          * <p>
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/tablecol/TableColumnOrderForCollectionTypeAbstract.java b/api/applib/src/main/java/org/apache/isis/applib/services/tablecol/TableColumnOrderForCollectionTypeAbstract.java
new file mode 100644
index 0000000..4d604e3
--- /dev/null
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/tablecol/TableColumnOrderForCollectionTypeAbstract.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.applib.services.tablecol;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+
+// tag::refguide[]
+@RequiredArgsConstructor
+public abstract class TableColumnOrderForCollectionTypeAbstract<T>
+        implements TableColumnOrderService {
+
+    private final Class<T> collectionType;
+
+    public final List<String> orderParented(
+            final Object parent,
+            final String collectionId,
+            final Class<?> collectionType,
+            final List<String> propertyIds) {
+        if (!this.collectionType.isAssignableFrom(collectionType)) {
+            return propertyIds;
+        }
+        return orderParented(parent, collectionId, propertyIds);
+    }
+
+    protected List<String> orderParented(
+            final Object parent,
+            final String collectionId,
+            final List<String> propertyIds) {
+        return propertyIds;
+    }
+
+    public final List<String> orderStandalone(
+            final Class<?> collectionType,
+            final List<String> propertyIds) {
+        if (this.collectionType.isAssignableFrom(collectionType)) {
+            return propertyIds;
+        }
+        return orderStandalone(propertyIds);
+    }
+
+    protected List<String> orderStandalone(
+            final List<String> propertyIds) {
+        return propertyIds;
+    }
+
+}
+// end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java b/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
index fb5d805..f308df4 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
@@ -85,23 +85,8 @@ public interface TransactionService {
      */
     // tag::refguide[]
     <T> T executeWithinTransaction(Supplier<T> task);       // <.>
-
     // end::refguide[]
 
-//   the executeWithinNewTransaction at time of writing is incorrect (doesn't create a new xactn).
-//   not sure there's any need for these additional methods?
-//
-//    /**
-//     * Runs given {@code task} within its own (new) transactional boundary.
-//     * @param task
-//     */
-//    void executeWithinNewTransaction(Runnable task);        // <.>
-//
-//    /**
-//     * Runs given {@code task} within its own (new) transactional boundary.
-//     * @param task
-//     */
-//    <T> T executeWithinNewTransaction(Supplier<T> task);    // <.>
 
     // tag::refguide[]
 }
diff --git a/api/applib/src/main/java/org/apache/isis/applib/util/ToString.java b/api/applib/src/main/java/org/apache/isis/applib/util/ToString.java
index a11a431..8893742 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/util/ToString.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/util/ToString.java
@@ -41,7 +41,7 @@ public class ToString<T> {
         return new ToString<>(name, getter, false);
     }
 
-    public static <T> ToString<T> toStringOmmitIfAbsent(String name, Function<? super T, ?> getter) {
+    public static <T> ToString<T> toStringOmitIfAbsent(String name, Function<? super T, ?> getter) {
         Objects.requireNonNull(name);
         Objects.requireNonNull(getter);
         return new ToString<>(name, getter, true);
@@ -49,10 +49,10 @@ public class ToString<T> {
 
     private final List<String> names = _Lists.newArrayList();
     private final List<Function<? super T, ?>> getters = _Lists.newArrayList();
-    private final BitSet ommitIfAbsent = new BitSet();
+    private final BitSet omitIfAbsent = new BitSet();
 
-    private ToString(String name, Function<? super T, ?> getter, boolean ommitIfAbsent) {
-        addBit(ommitIfAbsent);
+    private ToString(String name, Function<? super T, ?> getter, boolean omitIfAbsent) {
+        addBit(omitIfAbsent);
         names.add(name);
         getters.add(getter);
     }
@@ -66,7 +66,7 @@ public class ToString<T> {
         return this;
     }
 
-    public ToString<T> thenToStringOmmitIfAbsent(String name, Function<? super T, ?> getter){
+    public ToString<T> thenToStringOmitIfAbsent(String name, Function<? super T, ?> getter){
         Objects.requireNonNull(name);
         Objects.requireNonNull(getter);
         addBit(true);
@@ -95,13 +95,12 @@ public class ToString<T> {
 
         return String.format("%s{%s}",
 
-                //ommitIfAbsent.toString(),
                 target.getClass().getSimpleName(),
 
                 getters.stream()
                 .peek(__->index[0]++)
                 .map(getter->getter.apply(target))
-                .filter(value->value!=null || !ommitIfAbsent.get(index[0]))
+                .filter(value->value!=null || !omitIfAbsent.get(index[0]))
                 .map(valueToStringFunction)
                 .map(valueLiteral->names.get(index[0])+"="+valueLiteral)
                 .collect(Collectors.joining(", "))
@@ -114,9 +113,9 @@ public class ToString<T> {
     private void addBit(boolean bit) {
         final int index = names.size();
         if(bit) {
-            ommitIfAbsent.set(index);
+            omitIfAbsent.set(index);
         } else {
-            ommitIfAbsent.clear(index);
+            omitIfAbsent.clear(index);
         }
     }
 
diff --git a/api/applib/src/main/java/org/apache/isis/applib/util/schema/CommandDtoUtils.java b/api/applib/src/main/java/org/apache/isis/applib/util/schema/CommandDtoUtils.java
index bb7a815..9b6c93b0 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/util/schema/CommandDtoUtils.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/util/schema/CommandDtoUtils.java
@@ -63,6 +63,10 @@ public final class CommandDtoUtils {
         }
     }
 
+    public static CommandDto clone(final CommandDto commandDto) {
+        return fromXml(toXml(commandDto));
+    }
+
     public static CommandDto fromXml(final String xml) {
         return fromXml(new StringReader(xml));
     }
diff --git a/commons/src/main/java/org/apache/isis/core/commons/internal/exceptions/_Exceptions.java b/commons/src/main/java/org/apache/isis/core/commons/internal/exceptions/_Exceptions.java
index 741d271..8899e5c 100644
--- a/commons/src/main/java/org/apache/isis/core/commons/internal/exceptions/_Exceptions.java
+++ b/commons/src/main/java/org/apache/isis/core/commons/internal/exceptions/_Exceptions.java
@@ -27,6 +27,7 @@ import java.util.Optional;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import javax.annotation.Nullable;
@@ -270,6 +271,19 @@ public final class _Exceptions {
                 .limit(maxLines);
     }
 
+    public static final String asStacktrace(@Nullable Throwable ex, int maxLines, String delimiter) {
+        return _Exceptions.streamStacktraceLines(ex, maxLines)
+                .collect(Collectors.joining(delimiter));
+    }
+
+    public static final String asStacktrace(@Nullable Throwable ex, int maxLines) {
+        return asStacktrace(ex, maxLines, "\n");
+    }
+
+    public static final String asStacktrace(@Nullable Throwable ex) {
+        return asStacktrace(ex, 1000);
+    }
+
     /**
      * Dumps the current thread's stack-trace onto the given {@code writer}.
      * @param writer
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/Other.adoc b/core/config/src/main/adoc/modules/config/pages/sections/Other.adoc
index 8d2f543..369e82c 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/Other.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/Other.adoc
@@ -15,7 +15,7 @@ include::../section-hooks/Other~pre.adoc[]
 [[isis.as-map]]
 isis.as-map
 
-|
+| 
 | null
 
 
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/_nav.adoc b/core/config/src/main/adoc/modules/config/pages/sections/_nav.adoc
index 50051f8..fa17556 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/_nav.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/_nav.adoc
@@ -2,7 +2,7 @@
 ** xref:refguide:config:sections/isis.core.meta-model.adoc[Core MetaModel]
 ** xref:refguide:config:sections/isis.core.meta-model.introspector.adoc[Core MetaModel Introspection]
 ** xref:refguide:config:sections/isis.core.meta-model.validator.adoc[MetaModel Validator]
-** xref:refguide:config:sections/isis.core.runtime.adoc[Core Runtime Services configurations]
+** xref:refguide:config:sections/isis.core.runtime.adoc[Core Runtime configurations]
 ** xref:refguide:config:sections/isis.core.runtime-services.adoc[Core Runtime Services configurations]
 ** xref:refguide:config:sections/isis.security.shiro.adoc[Shiro Security Implementation]
 ** xref:refguide:config:sections/isis.persistence.jdo-datanucleus.adoc[JDO DataNucleus]
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/isis.applib.adoc b/core/config/src/main/adoc/modules/config/pages/sections/isis.applib.adoc
index 34d6d06..28b5b43 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/isis.applib.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/isis.applib.adoc
@@ -17,7 +17,7 @@ isis.applib.annotation. +
 action-layout.css-class-fa. +
 patterns
 
-|
+| 
 | Provides a mapping of patterns to font-awesome CSS classes, where the pattern is used to match against the name of the action method in order to determine a CSS class to use, for example on the action's menu icon if rendered by the Wicket viewer.
 
 Providing a default set of patterns encourages a common set of verbs to be used.
@@ -30,7 +30,7 @@ The font awesome class for individual actions can be overridden using ``ActionLa
 isis.applib.annotation. +
 action-layout.css-class.patterns
 
-|
+| 
 | Provides a mapping of patterns to CSS classes, where the pattern is used to match against the name of the action method in order to determine a CSS class to use, for example on the action's button if rendered by the Wicket viewer.
 
 Providing a default set of patterns encourages a common set of verbs to be used.
@@ -43,10 +43,8 @@ The CSS class for individual actions can be overridden using ``ActionLayout#cssC
 isis.applib.annotation.action. +
 command
 
-|
-| The default for whether action invocations should be reified as a ``Command`` using the ``CommandService``, possibly so that the actual execution of the action can be deferred until later (background execution) or replayed against a copy of the system.
-
-In particular, the ``CommandWithDto`` implementation of ``Command`` represents the action invocation memento (obtained using ``CommandWithDto#asDto()``) as a ``CommandDto``.
+| 
+| The default for whether action invocations should be reified as a ``Command`` using the ``CommandService``, either for auditing or for replayed against a secondary system, eg for regression testing.
 
 This setting can be overridden on a case-by-case basis using ``Action#command()``.
 
@@ -73,7 +71,7 @@ The algorithm for determining whether (and what type of) an event is actually se
 isis.applib.annotation.action. +
 explicit
 
-|
+| 
 | Whether or not a public method needs to be annotated with @``Action`` in order to be picked up as an action in the metamodel.
 
 
@@ -82,7 +80,7 @@ explicit
 isis.applib.annotation.action. +
 publishing
 
-|
+| 
 | The default for whether action invocations should be sent through to the ``PublisherService`` for publishing.
 
 The service's publish method is called only once per transaction, with ``Execution`` collecting details of the identity of the target object, the action invoked, the action arguments and the returned object (if any).
@@ -95,7 +93,7 @@ This setting can be overridden on a case-by-case basis using ``Action#publishing
 isis.applib.annotation. +
 collection-layout.default-view
 
-|
+| 
 | Defines the initial view to display collections when rendered.
 
 The value of this can be overridden on a case-by-case basis using ``CollectionLayout#defaultView()``. Note that this default configuration property is an enum and so defines only a fixed number of values, whereas the annotation returns a string; this is to allow for flexibility that individual viewers might support their own additional types. For example, the Wicket viewer supports
@@ -136,7 +134,7 @@ domain-object-layout. +
 css-class-ui-event. +
 post-for-default
 
-|  true
+| 
 | Influences whether an ``CssClassUiEvent`` should be published (on the internal ``EventBusService``) whenever a domain object is about to be rendered in the UI - thereby allowing subscribers to optionally ``CssClassUiEvent#setCssClass(String)`` change) the CSS classes that are used.
 
 The algorithm for determining whether (and what type of) an event is sent depends on the value of the ``DomainObjectLayout#cssClassUiEvent()`` @DomainObjectLayout(cssClassEvent=...)} for the domain object in question.
@@ -145,6 +143,8 @@ The algorithm for determining whether (and what type of) an event is sent depend
 * If set to some subtype of CssClassUiEvent.Default, then an event is sent _if and only if_ this configuration setting is set.
 * If set to any other subtype, then an event _is_ sent.
 
+The default is ``false``, because otherwise the mere presence of ``@DomainObjectLayout`` (perhaps for some attribute other than this one) will cause any imperative ``cssClass()`` method to be ignored.
+
 
 |
 [[isis.applib.annotation.domain-object-layout.icon-ui-event.post-for-default]]
@@ -152,7 +152,7 @@ isis.applib.annotation. +
 domain-object-layout.icon-ui-event. +
 post-for-default
 
-|  true
+| 
 | Influences whether an ``IconUiEvent`` should be published (on the internal ``EventBusService``) whenever a domain object is about to be rendered in the UI - thereby allowing subscribers to optionally ``IconUiEvent#setIconName(String)`` change) the icon that is used.
 
 The algorithm for determining whether (and what type of) an event is sent depends on the value of the ``DomainObjectLayout#iconUiEvent()`` @DomainObjectLayout(iconEvent=...)} for the domain object in question.
@@ -161,6 +161,8 @@ The algorithm for determining whether (and what type of) an event is sent depend
 * If set to some subtype of IconUiEvent.Default, then an event is sent _if and only if_ this configuration setting is set.
 * If set to any other subtype, then an event _is_ sent.
 
+The default is ``false``, because otherwise the mere presence of ``@DomainObjectLayout`` (perhaps for some attribute other than this one) will cause any imperative ``iconName()`` method to be ignored.
+
 
 |
 [[isis.applib.annotation.domain-object-layout.layout-ui-event.post-for-default]]
@@ -168,7 +170,7 @@ isis.applib.annotation. +
 domain-object-layout. +
 layout-ui-event.post-for-default
 
-|  true
+| 
 | Influences whether an ``LayoutUiEvent`` should be published (on the internal ``EventBusService``) whenever a domain object is about to be rendered in the UI - thereby allowing subscribers to optionally ``LayoutUiEvent#setLayout(String)`` change) the layout that is used.
 
 If a different layout value has been set, then a layout in the form ``xml`` use used (where ``zzz`` is the name of the layout).
@@ -179,6 +181,8 @@ The algorithm for determining whether (and what type of) an event is sent depend
 * If set to some subtype of LayoutUiEvent.Default, then an event is sent _if and only if_ this configuration setting is set.
 * If set to any other subtype, then an event _is_ sent.
 
+The default is ``false``, because otherwise the mere presence of ``@DomainObjectLayout`` (perhaps for some attribute other than this one) will cause any imperative ``layout()`` method to be ignored.
+
 
 |
 [[isis.applib.annotation.domain-object-layout.paged]]
@@ -197,7 +201,7 @@ isis.applib.annotation. +
 domain-object-layout. +
 title-ui-event.post-for-default
 
-|  true
+| 
 | Influences whether an ``TitleUiEvent`` should be published (on the internal ``EventBusService``) whenever a domain object is about to be rendered in the UI - thereby allowing subscribers to optionally ``TitleUiEvent#setTitle(String)`` change) the title that is used.
 
 The algorithm for determining whether (and what type of) an event is sent depends on the value of the ``DomainObjectLayout#titleUiEvent()`` @DomainObjectLayout(titleEvent=...)} for the domain object in question.
@@ -206,13 +210,15 @@ The algorithm for determining whether (and what type of) an event is sent depend
 * If set to some subtype of TitleUiEvent.Default, then an event is sent _if and only if_ this configuration setting is set.
 * If set to any other subtype, then an event _is_ sent.
 
+The default is ``false``, because otherwise the mere presence of ``@DomainObjectLayout`` (perhaps for some attribute other than this one) will cause any imperative ``title()`` method to be ignored.
+
 
 |
 [[isis.applib.annotation.domain-object.auditing]]
 isis.applib.annotation. +
 domain-object.auditing
 
-|
+| 
 | The default for whether _domain entities_ should be audited or not (meaning that any changes are sent through to the ``AuditerService``.
 
 This setting can be overridden on a case-by-case basis using ``DomainObject#auditing()`` DomainObject#getAuditing()}
@@ -242,7 +248,7 @@ The algorithm for determining whether (and what type of) an event is sent depend
 isis.applib.annotation. +
 domain-object.editing
 
-|
+| 
 | The default for whether the properties of domain objects can be edited, or whether instead they can be modified only using actions (or programmatically as a side-effect of actions on other objects).
 
 This setting can be overridden on a case-by-case basis using DomainObject#getEditing()
@@ -310,7 +316,7 @@ Note: this applies only to domain entities, not to view models.
 isis.applib.annotation. +
 domain-object.publishing
 
-|
+| 
 | The default for whether the identities of changed objects should be sent through to the ``PublisherService`` for publishing.
 
 The service's publish method is called only once per transaction, with ``PublishedObjects`` collecting details of all changed domain objects.
@@ -382,7 +388,7 @@ Note: this applies only to domain entities, not to view models.
 isis.applib.annotation. +
 parameter-layout.label-position
 
-|
+| 
 | Defines the default position for the label for an action parameter.
 
 Can be overridden on a case-by-case basis using ``ParameterLayout#labelPosition()``.
@@ -395,7 +401,7 @@ If left as ``LabelPosition#NOT_SPECIFIED`` and not overridden, then the position
 isis.applib.annotation. +
 property-layout.label-position
 
-|
+| 
 | Defines the default position for the label for a domain object property.
 
 Can be overridden on a case-by-case basis using ``ParameterLayout#labelPosition()``.
@@ -408,12 +414,10 @@ If left as ``LabelPosition#NOT_SPECIFIED`` and not overridden, then the position
 isis.applib.annotation.property. +
 command
 
-|
-| The default for whether property edits should be reified as a ``Command`` using the ``CommandService``, possibly so that the actual execution of the property edit can be deferred until later (background execution) or replayed against a copy of the system.
-
-In particular, the ``CommandWithDto`` implementation of ``Command`` represents the action invocation memento (obtained using ``CommandWithDto#asDto()``) as a ``CommandDto``.
+| 
+| The default for whether property edits should be reified as a ``Command`` using the ``CommandService``, for example for auditing, or to be replayed against a secondary system, for regression testing.
 
-This setting can be overridden on a case-by-case basis using ``Action#command()``.
+This setting can be overridden on a case-by-case basis using ``Property#command()``.
 
 
 |
@@ -438,7 +442,7 @@ The algorithm for determining whether (and what type of) an event is actually se
 isis.applib.annotation.property. +
 publishing
 
-|
+| 
 | The default for whether property edits should be sent through to the ``PublisherService`` for publishing.
 
 The service's publish method is called only once per transaction, with ``Execution`` collecting details of the identity of the target object, the property edited, and the new value of the property.
@@ -519,7 +523,7 @@ isis.applib.annotation.view-model. +
 validation.semantic-checking. +
 enable
 
-|
+| 
 | Whether to check for inconsistencies between the usage of ``DomainObject``, ``ViewModel``, ``DomainObjectLayout`` and ``ViewModelLayout``.
 
 
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/isis.core.meta-model.adoc b/core/config/src/main/adoc/modules/config/pages/sections/isis.core.meta-model.adoc
index f9aec4a..a194ad1 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/isis.core.meta-model.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/isis.core.meta-model.adoc
@@ -28,7 +28,7 @@ isis.core.meta-model. +
 programming-model. +
 ignore-deprecated
 
-|
+| 
 | If set, then any aspects of the programming model (as implemented by ``FacetFactory``s that have been indicated as deprecated will simply be ignored/excluded from the metamodel.
 
 
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/isis.core.meta-model.introspector.adoc b/core/config/src/main/adoc/modules/config/pages/sections/isis.core.meta-model.introspector.adoc
index e12efa6..d288d75 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/isis.core.meta-model.introspector.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/isis.core.meta-model.introspector.adoc
@@ -27,7 +27,7 @@ Only applies if the introspector is configured to perform full introspection up-
 isis.core.meta-model.introspector. +
 mode
 
-|
+| 
 | Whether all known types should be fully introspected as part of the bootstrapping, or should only be partially introspected initially.
 
 Leaving this as lazy means that there's a chance that metamodel validation errors will not be discovered during bootstrap. That said, metamodel validation is still run incrementally for any classes introspected lazily after initial bootstrapping (unless ``#isValidateIncrementally()`` is disabled.
@@ -38,8 +38,10 @@ Leaving this as lazy means that there's a chance that metamodel validation error
 isis.core.meta-model.introspector. +
 parallelize
 
-|  true
-| Whether to perform introspection in parallel.
+| 
+| Whether to perform introspection in parallel. Meant to speed up bootstrapping.
+
+For now this is _experimental_. Leave this disabled (the default).
 
 
 |
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/isis.core.meta-model.validator.adoc b/core/config/src/main/adoc/modules/config/pages/sections/isis.core.meta-model.validator.adoc
index 991ede3..34b4a40 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/isis.core.meta-model.validator.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/isis.core.meta-model.validator.adoc
@@ -50,7 +50,7 @@ It is _highly advisable_ to leave this set as enabled (the default), and to also
 isis.core.meta-model.validator. +
 explicit-object-type
 
-|
+| 
 | Whether to ensure that the object type of all objects must be specified explicitly, using either ``DomainObject#objectType()`` or ``DomainService#objectType()``.
 
 It is _highly advisable_ to leave this set as enabled (the default). These object types should also (of course) be unique - that can be checked by setting the ``#isEnsureUniqueObjectTypes()`` config property.
@@ -71,7 +71,7 @@ date-time-type-adapter
 isis.core.meta-model.validator. +
 jaxb-view-model.no-arg-constructor
 
-|
+| 
 | If set, then ensures that all JAXB-style view models have a no-arg constructor.
 
 
@@ -126,7 +126,7 @@ jdoql.variables-clause
 isis.core.meta-model.validator. +
 no-params-only
 
-|
+| 
 | If set, then checks that the supports ``hideXxx`` and ``disableXxx`` methods for actions do not have take parameters.
 
 Historically, the programming model allowed these methods to accept the same number of parameters as the action method to which they relate, the rationale being for similarity with the ``validateXxx`` method. However, since these parameters serve no function, the programming model has been simplified so that these supporting methods are discovered if they have exactly no parameters.
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/isis.core.runtime-services.adoc b/core/config/src/main/adoc/modules/config/pages/sections/isis.core.runtime-services.adoc
index c330019..23be405 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/isis.core.runtime-services.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/isis.core.runtime-services.adoc
@@ -16,7 +16,7 @@ include::../section-hooks/isis.core.runtime-services~pre.adoc[]
 isis.core.runtime-services. +
 application-features.init
 
-|
+| 
 | Whether the ``ApplicationFeatureRepository`` (or the default implementation of that service, at least) should compute the set of ``ApplicationFeature`` that describe the metamodel eagerly, or lazily.
 
 
@@ -25,7 +25,7 @@ application-features.init
 isis.core.runtime-services.email. +
 override.bcc
 
-|
+| 
 | Intended for testing purposes only, if set then the requested ``bcc:`` of the email will be ignored, and instead sent to this email address instead.
 
 
@@ -34,7 +34,7 @@ override.bcc
 isis.core.runtime-services.email. +
 override.cc
 
-|
+| 
 | Intended for testing purposes only, if set then the requested ``cc:`` of the email will be ignored, and instead sent to this email address instead.
 
 
@@ -43,7 +43,7 @@ override.cc
 isis.core.runtime-services.email. +
 override.to
 
-|
+| 
 | Intended for testing purposes only, if set then the requested ``to:`` of the email will be ignored, and instead sent to this email address instead.
 
 
@@ -61,7 +61,7 @@ port
 isis.core.runtime-services.email. +
 sender.address
 
-|
+| 
 | Specifies the email address of the user sending the email.
 
 If the username is not specified, is also used as the username to connect to the SMTP service.
@@ -74,7 +74,7 @@ This configuration property is mandatory (for the default implementation of the
 isis.core.runtime-services.email. +
 sender.hostname
 
-|
+| 
 | Specifies the host running the SMTP service.
 
 If not specified, then the value used depends upon the email implementation. The default implementation will use the ``host`` system property.
@@ -85,7 +85,7 @@ If not specified, then the value used depends upon the email implementation. The
 isis.core.runtime-services.email. +
 sender.password
 
-|
+| 
 | Specifies the password (corresponding to the username to connect to the SMTP service.
 
 This configuration property is mandatory (for the default implementation of the ``EmailService``, at least).
@@ -96,7 +96,7 @@ This configuration property is mandatory (for the default implementation of the
 isis.core.runtime-services.email. +
 sender.username
 
-|
+| 
 | Specifies the username to use to connect to the SMTP service.
 
 If not specified, then the sender's email address will be used instead.
@@ -126,7 +126,7 @@ isis.core.runtime-services.email. +
 throw-exception-on-fail
 
 |  true
-| If an email fails to send, whether to propagate the exception (meaning that potentially the end-user might see the exception), or whether instead to just indicate failure through the return value of the method (\{@link org.apache.isis.applib.services.email.EmailService#send(List, List, List, String, String, DataSource...)) that's being called.
+| If an email fails to send, whether to propagate the exception (meaning that potentially the end-user might see the exception), or whether instead to just indicate failure through the return value of the method (List, List, String, String, DataSource...) that's being called.
 
 
 |
@@ -143,7 +143,7 @@ tls.enabled
 isis.core.runtime-services. +
 exception-recognizer.jdo.disable
 
-|
+| 
 | Whether the ``ExceptionRecognizer`` implementation for JDO/DataNucleus object store - which attempts to sanitize any exceptions arising from that object store - should be disabled (meaning that exceptions will potentially propagate as more serious to the end user).
 
 
@@ -153,7 +153,7 @@ isis.core.runtime-services. +
 repository-service. +
 disable-auto-flush
 
-|
+| 
 | Normally any queries are automatically preceded by flushing pending executions.
 
 This key allows this behaviour to be disabled.
@@ -166,7 +166,7 @@ Originally introduced as part of ISIS-1134 (fixing memory leaks in the objectsto
 isis.core.runtime-services. +
 translation.po.mode
 
-|
+| 
 | Specifies the initial mode for obtaining/discovering translations.
 
 There are three modes:
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/isis.core.runtime.adoc b/core/config/src/main/adoc/modules/config/pages/sections/isis.core.runtime.adoc
index ef61cd5..0d78569 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/isis.core.runtime.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/isis.core.runtime.adoc
@@ -15,7 +15,7 @@ include::../section-hooks/isis.core.runtime~pre.adoc[]
 [[isis.core.runtime.locale]]
 isis.core.runtime.locale
 
-|
+| 
 | If set, then overrides the application's ``Locale#getDefault()``
 
 
@@ -23,7 +23,7 @@ isis.core.runtime.locale
 [[isis.core.runtime.timezone]]
 isis.core.runtime.timezone
 
-|
+| 
 | If set, then override's the application's timezone.
 
 
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/isis.extensions.adoc b/core/config/src/main/adoc/modules/config/pages/sections/isis.extensions.adoc
index 3e55561..9f3426a 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/isis.extensions.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/isis.extensions.adoc
@@ -12,11 +12,117 @@ include::../section-hooks/isis.extensions~pre.adoc[]
 |Default
 |Description
 |
+[[isis.extensions.command-replay.primary.base-url]]
+isis.extensions.command-replay. +
+primary.base-url
+
+| 
+| null
+
+
+|
+[[isis.extensions.command-replay.primary.base-url-end-user]]
+isis.extensions.command-replay. +
+primary.base-url-end-user
+
+| 
+| null
+
+
+|
+[[isis.extensions.command-replay.primary.batch-size]]
+isis.extensions.command-replay. +
+primary.batch-size
+
+|  10
+| null
+
+
+|
+[[isis.extensions.command-replay.primary.password]]
+isis.extensions.command-replay. +
+primary.password
+
+| 
+| null
+
+
+|
+[[isis.extensions.command-replay.primary.user]]
+isis.extensions.command-replay. +
+primary.user
+
+| 
+| null
+
+
+|
+[[isis.extensions.command-replay.secondary.analyser.exception.enabled]]
+isis.extensions.command-replay. +
+secondary.analyser.exception. +
+enabled
+
+|  true
+| null
+
+
+|
+[[isis.extensions.command-replay.secondary.analyser.result.enabled]]
+isis.extensions.command-replay. +
+secondary.analyser.result.enabled
+
+|  true
+| null
+
+
+|
+[[isis.extensions.command-replay.secondary.quartz-replicate-and-replay-job.repeat-interval]]
+isis.extensions.command-replay. +
+secondary. +
+quartz-replicate-and-replay-job. +
+repeat-interval
+
+|  10000
+| Number of milliseconds before running again.
+
+
+|
+[[isis.extensions.command-replay.secondary.quartz-replicate-and-replay-job.start-delay]]
+isis.extensions.command-replay. +
+secondary. +
+quartz-replicate-and-replay-job. +
+start-delay
+
+|  15000
+| Number of milliseconds before starting the job.
+
+
+|
+[[isis.extensions.command-replay.secondary.quartz-session.roles]]
+isis.extensions.command-replay. +
+secondary.quartz-session.roles
+
+|  isisModuleExtCommandReplaySecondar +
+yRole
+| null
+
+
+|
+[[isis.extensions.command-replay.secondary.quartz-session.user]]
+isis.extensions.command-replay. +
+secondary.quartz-session.user
+
+|  isisModuleExtCommandReplaySecondar +
+yUser
+| The user that runs the replay session secondary.
+
+
+|
 [[isis.extensions.cors.allowed-headers]]
 isis.extensions.cors. +
 allowed-headers
 
-|
+| 
 | Which HTTP headers are allowed in a CORS request.
 
 For more information, check the usage of the ``headers`` init parameter for https://github.com/eBay/cors-filter[EBay CORSFilter].
@@ -27,7 +133,7 @@ For more information, check the usage of the ``headers`` init parameter for http
 isis.extensions.cors. +
 allowed-methods
 
-|
+| 
 | Which HTTP methods are permitted in a CORS request.
 
 For more information, check the usage of the ``methods`` init parameter for https://github.com/eBay/cors-filter[EBay CORSFilter].
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/isis.legacy.adoc b/core/config/src/main/adoc/modules/config/pages/sections/isis.legacy.adoc
index af36d67..72336de 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/isis.legacy.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/isis.legacy.adoc
@@ -16,7 +16,7 @@ include::../section-hooks/isis.legacy~pre.adoc[]
 isis.legacy.value-types.money. +
 currency
 
-|
+| 
 | Configures the default currency code used by ``MoneyValueSemanticsProvider``. @deprecated
 
 
@@ -25,7 +25,7 @@ currency
 isis.legacy.value-types.percentage. +
 format
 
-|
+| 
 | Configures the formats understood by ``PercentageValueSemanticsProvider``. @deprecated
 
 
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/isis.persistence.jdo-datanucleus.impl.adoc b/core/config/src/main/adoc/modules/config/pages/sections/isis.persistence.jdo-datanucleus.impl.adoc
index 95f99cc..986e28a 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/isis.persistence.jdo-datanucleus.impl.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/isis.persistence.jdo-datanucleus.impl.adoc
@@ -17,7 +17,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus. +
 ConnectionFactory2Name
 
-|
+| 
 | null
 
 
@@ -27,7 +27,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus. +
 ConnectionFactoryName
 
-|
+| 
 | null
 
 
@@ -37,7 +37,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus. +
 ConnectionPasswordDecrypter
 
-|
+| 
 | null
 
 
@@ -47,7 +47,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus. +
 PersistenceUnitLoadClasses
 
-|
+| 
 | null
 
 
@@ -56,7 +56,7 @@ PersistenceUnitLoadClasses
 isis.persistence.jdo-datanucleus. +
 impl.datanucleus.cache.level2.mode
 
-|
+| 
 | Values of javax.persistence.SharedCacheMode, capitalized
 
 
@@ -81,7 +81,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus. +
 connection-factory-name
 
-|
+| 
 | The JNDI name for a connection factory for transactional connections.
 
 For RBDMS, it must be a JNDI name that points to a javax.sql.DataSource object.
@@ -97,7 +97,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus. +
 connection-factory2-name
 
-|
+| 
 | The JNDI name for a connection factory for non-transactional connections.
 
 For RBDMS, it must be a JNDI name that points to a javax.sql.DataSource object.
@@ -113,7 +113,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus. +
 connection-password-decrypter
 
-|
+| 
 | Name of a class that implements ``DecryptionProvider`` and should only be specified if the password is encrypted in the persistence properties.
 
 See also ``json`` (camelCasing instead of kebab-casing).
@@ -126,7 +126,7 @@ NOTE: this config property isn't used by the framework, but is provided as a con
 isis.persistence.jdo-datanucleus. +
 impl.datanucleus.identifier.case
 
-|
+| 
 | null
 
 
@@ -150,7 +150,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus.objectProvider. +
 className
 
-|
+| 
 | null
 
 
@@ -176,7 +176,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus. +
 persistenceByReachabilityAtCommit
 
-|
+| 
 | null
 
 
@@ -186,7 +186,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus.schema. +
 auto-create-all
 
-|
+| 
 | Whether DN should automatically create the database schema on bootstrapping.
 
 This should be set to ``true`` when running against an in-memory database, but set to ``false`` when running against a persistent database (use something like flyway instead to manage schema evolution).
@@ -202,7 +202,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus.schema. +
 auto-create-database
 
-|
+| 
 | Previously we defaulted this property to "true", but that could cause the target database to be modified
 
 See also ``json`` (camelCasing instead of kebab-casing).
@@ -216,7 +216,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus.schema. +
 autoCreateAll
 
-|
+| 
 | null
 
 
@@ -226,7 +226,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus.schema. +
 autoCreateDatabase
 
-|
+| 
 | null
 
 
@@ -248,7 +248,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus.schema. +
 validateAll
 
-|
+| 
 | null
 
 
@@ -258,7 +258,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus.schema. +
 validateConstraints
 
-|
+| 
 | null
 
 
@@ -268,7 +268,7 @@ isis.persistence.jdo-datanucleus. +
 impl.datanucleus.schema. +
 validateTables
 
-|
+| 
 | null
 
 
@@ -277,7 +277,7 @@ validateTables
 isis.persistence.jdo-datanucleus. +
 impl.datanucleus.transaction-type
 
-|
+| 
 | Type of transaction to use.
 
 If running under JavaSE the default is RESOURCE_LOCAL, and if running under JavaEE the default is JTA.
@@ -293,7 +293,7 @@ isis.persistence.jdo-datanucleus. +
 impl.javax.jdo. +
 PersistenceManagerFactoryClass
 
-|
+| 
 | null
 
 
@@ -303,7 +303,7 @@ isis.persistence.jdo-datanucleus. +
 impl.javax.jdo.option. +
 ConnectionDriverName
 
-|
+| 
 | null
 
 
@@ -313,7 +313,7 @@ isis.persistence.jdo-datanucleus. +
 impl.javax.jdo.option. +
 ConnectionPassword
 
-|
+| 
 | null
 
 
@@ -323,7 +323,7 @@ isis.persistence.jdo-datanucleus. +
 impl.javax.jdo.option. +
 ConnectionURL
 
-|
+| 
 | null
 
 
@@ -333,7 +333,7 @@ isis.persistence.jdo-datanucleus. +
 impl.javax.jdo.option. +
 ConnectionUserName
 
-|
+| 
 | null
 
 
@@ -343,7 +343,7 @@ isis.persistence.jdo-datanucleus. +
 impl.javax.jdo.option. +
 connection-driver-name
 
-|
+| 
 | JDBC driver used by JDO/DataNucleus object store to connect.
 
 See also ``json`` (PascalCasing instead of kebab-casing).
@@ -357,7 +357,7 @@ isis.persistence.jdo-datanucleus. +
 impl.javax.jdo.option. +
 connection-password
 
-|
+| 
 | Password for the user account used by JDO/DataNucleus object store to connect.
 
 See also ``json`` (PascalCasing instead of kebab-casing).
@@ -371,7 +371,7 @@ isis.persistence.jdo-datanucleus. +
 impl.javax.jdo.option. +
 connection-url
 
-|
+| 
 | URL used by JDO/DataNucleus object store to connect.
 
 See also ``json`` (PascalCasing instead of kebab-casing).
@@ -385,7 +385,7 @@ isis.persistence.jdo-datanucleus. +
 impl.javax.jdo.option. +
 connection-user-name
 
-|
+| 
 | User account used by JDO/DataNucleus object store to connect.
 
 See also ``json`` (PascalCasing instead of kebab-casing).
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/isis.security.shiro.adoc b/core/config/src/main/adoc/modules/config/pages/sections/isis.security.shiro.adoc
index f18f5a9..dac0e41 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/isis.security.shiro.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/isis.security.shiro.adoc
@@ -17,7 +17,7 @@ isis.security.shiro. +
 auto-logout-if-already- +
 authenticated
 
-|
+| 
 | If the Shiro subject is found to be still authenticated, then will be logged out anyway and then re-authenticated.
 
 Applies only to the Restful Objects viewer.
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/isis.testing.adoc b/core/config/src/main/adoc/modules/config/pages/sections/isis.testing.adoc
index d0091dd..c910945 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/isis.testing.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/isis.testing.adoc
@@ -16,7 +16,7 @@ include::../section-hooks/isis.testing~pre.adoc[]
 isis.testing.fixtures. +
 initial-script
 
-|
+| 
 | Indicates the fixture script class to run initially.
 
 Intended for use when prototyping against an in-memory database (but will run in production mode as well if required).
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/isis.value-types.adoc b/core/config/src/main/adoc/modules/config/pages/sections/isis.value-types.adoc
index 3aaa4ff..a026acc 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/isis.value-types.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/isis.value-types.adoc
@@ -16,7 +16,7 @@ include::../section-hooks/isis.value-types~pre.adoc[]
 isis.value-types.primitives. +
 integer.format
 
-|
+| 
 | null
 
 
@@ -25,7 +25,7 @@ integer.format
 isis.value-types.java-lang.byte. +
 format
 
-|
+| 
 | Configures the number format understood by ``ByteValueSemanticsProviderAbstract``. @deprecated
 
 
@@ -34,7 +34,7 @@ format
 isis.value-types.java-lang.double. +
 format
 
-|
+| 
 | Configures the number format understood by ``DoubleValueSemanticsProviderAbstract``. @deprecated
 
 
@@ -43,7 +43,7 @@ format
 isis.value-types.java-lang.float. +
 format
 
-|
+| 
 | Configures the number format understood by ``FloatValueSemanticsProviderAbstract``. @deprecated
 
 
@@ -52,7 +52,7 @@ format
 isis.value-types.java-lang.long. +
 format
 
-|
+| 
 | Configures the number format understood by ``LongValueSemanticsProviderAbstract``. @deprecated
 
 
@@ -61,7 +61,7 @@ format
 isis.value-types.java-lang.short. +
 format
 
-|
+| 
 | Configures the number format understood by ``ShortValueSemanticsProviderAbstract``. @deprecated
 
 
@@ -70,7 +70,7 @@ format
 isis.value-types.java-math. +
 big-decimal.format
 
-|
+| 
 | Configures the number format understood by ``BigDecimalValueSemanticsProvider``. @deprecated
 
 
@@ -79,7 +79,7 @@ big-decimal.format
 isis.value-types.java-math. +
 big-integer.format
 
-|
+| 
 | Configures the number format understood by ``BigIntegerValueSemanticsProvider``. @deprecated
 
 
@@ -205,7 +205,7 @@ format
 isis.value-types.primitives.int. +
 format
 
-|
+| 
 | Configures the number format understood by ``IntValueSemanticsProviderAbstract``. @deprecated
 
 
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/isis.viewer.restfulobjects.adoc b/core/config/src/main/adoc/modules/config/pages/sections/isis.viewer.restfulobjects.adoc
index 3fcf60d..b0933aa 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/isis.viewer.restfulobjects.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/isis.viewer.restfulobjects.adoc
@@ -16,7 +16,7 @@ include::../section-hooks/isis.viewer.restfulobjects~pre.adoc[]
 isis.viewer.restfulobjects. +
 base-uri
 
-|
+| 
 | If left unset (the default), then the RO viewer will use the ``UriInfo`` (injected using ``Context``) to figure out the base Uri (used to render ``href``s).
 
 This will be correct much of the time, but will almost certainly be wrong if there is a reverse proxy.
@@ -29,7 +29,7 @@ If set, eg ``com/``, then this value will be used instead.
 isis.viewer.restfulobjects. +
 honor-ui-hints
 
-|
+| 
 | Whether to enable the ``x-ro-follow-links`` support, to minimize round trips.
 
 The RO viewer provides the capability for the client to set the optional ``x-ro-follow-links`` query parameter, as described in section 34.4 of the RO spec v1.0. If used, the resultant representation includes the result of following the associated link, but through a server-side "join", somewhat akin to GraphQL.
@@ -42,7 +42,7 @@ By default this functionality is disabled, this configuration property enables t
 isis.viewer.restfulobjects. +
 object-property-values-only
 
-|
+| 
 | When rendering domain objects, if set the representation returned is stripped back to a minimal set, excluding links to actions and collections and with a simplified representation of an object's properties.
 
 This is disabled by default. If enabled, then the representations returned are non-standard with respect to the RO Spec v1.0.
@@ -53,7 +53,7 @@ This is disabled by default. If enabled, then the representations returned are n
 isis.viewer.restfulobjects. +
 strict-accept-checking
 
-|
+| 
 | If set, then any unrecognised ``Accept`` headers will result in an HTTP _Not Acceptable_ response code (406).
 
 
@@ -62,7 +62,7 @@ strict-accept-checking
 isis.viewer.restfulobjects. +
 suppress-described-by-links
 
-|
+| 
 | If set, then the representations returned will omit any links to the formal domain-type representations.
 
 
@@ -71,7 +71,7 @@ suppress-described-by-links
 isis.viewer.restfulobjects. +
 suppress-member-disabled-reason
 
-|
+| 
 | If set, then - should there be an interaction with an action, property or collection that is disabled - then this will prevent the ``disabledReason`` reason from being added to the returned representation.
 
 This is disabled by default. If enabled, then the representations returned are non-standard with respect to the RO Spec v1.0.
@@ -82,7 +82,7 @@ This is disabled by default. If enabled, then the representations returned are n
 isis.viewer.restfulobjects. +
 suppress-member-extensions
 
-|
+| 
 | If set, then the ``x-isis-format`` key (under ``extensions``) for properties will be suppressed.
 
 This is disabled by default. If enabled, then the representations returned are non-standard with respect to the RO Spec v1.0.
@@ -93,7 +93,7 @@ This is disabled by default. If enabled, then the representations returned are n
 isis.viewer.restfulobjects. +
 suppress-member-id
 
-|
+| 
 | If set, then the ``id`` key for all members will be suppressed.
 
 This is disabled by default. If enabled, then the representations returned are non-standard with respect to the RO Spec v1.0.
@@ -104,7 +104,7 @@ This is disabled by default. If enabled, then the representations returned are n
 isis.viewer.restfulobjects. +
 suppress-member-links
 
-|
+| 
 | If set, then the detail link (in other words ``]``) for all members will be suppressed.
 
 This is disabled by default. If enabled, then the representations returned are non-standard with respect to the RO Spec v1.0.
@@ -115,7 +115,7 @@ This is disabled by default. If enabled, then the representations returned are n
 isis.viewer.restfulobjects. +
 suppress-update-link
 
-|
+| 
 | If set, then the update link (in other words `` ]`` to perform a bulk update of an object) will be suppressed.
 
 This is disabled by default. If enabled, then the representations returned are non-standard with respect to the RO Spec v1.0.
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/isis.viewer.wicket.adoc b/core/config/src/main/adoc/modules/config/pages/sections/isis.viewer.wicket.adoc
index 079205b..bd7ce2a 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/isis.viewer.wicket.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/isis.viewer.wicket.adoc
@@ -15,7 +15,7 @@ include::../section-hooks/isis.viewer.wicket~pre.adoc[]
 [[isis.viewer.wicket.ajax-debug-mode]]
 isis.viewer.wicket.ajax-debug-mode
 
-|
+| 
 | Whether the Ajax debug should be shown, by default this is disabled.
 
 
@@ -36,7 +36,7 @@ There is usually very little reason to change this from its default.
 isis.viewer.wicket.application. +
 about
 
-|
+| 
 | Label used on the about page.
 
 
@@ -45,7 +45,7 @@ about
 isis.viewer.wicket.application. +
 brand-logo-header
 
-|
+| 
 | Either the location of the image file (relative to the class-path resource root), or an absolute URL.
 
 This is rendered on the header panel. An image with a size of 160x40 works well. If not specified, the application.name is used instead.
@@ -56,7 +56,7 @@ This is rendered on the header panel. An image with a size of 160x40 works well.
 isis.viewer.wicket.application. +
 brand-logo-signin
 
-|
+| 
 | Either the location of the image file (relative to the class-path resource root), or an absolute URL.
 
 This is rendered on the sign-in page. An image with a size of 400x40 works well. If not specified, the application name is used instead.
@@ -66,7 +66,7 @@ This is rendered on the sign-in page. An image with a size of 400x40 works well.
 [[isis.viewer.wicket.application.css]]
 isis.viewer.wicket.application.css
 
-|
+| 
 | URL of file to read any custom CSS, relative to ``static`` package on the class path.
 
 A typical value is ``css``. This will result in this file being read from the ``static/css`` directory (because static resources such as CSS are mounted by Spring by default under ``static`` package).
@@ -77,7 +77,7 @@ A typical value is ``css``. This will result in this file being read from the ``
 isis.viewer.wicket.application. +
 favicon-content-type
 
-|
+| 
 | Specifies the content type of the favIcon, if any.
 
 
@@ -86,7 +86,7 @@ favicon-content-type
 isis.viewer.wicket.application. +
 favicon-url
 
-|
+| 
 | Specifies the URL to use of the favIcon.
 
 This is expected to be a local resource.
@@ -96,7 +96,7 @@ This is expected to be a local resource.
 [[isis.viewer.wicket.application.js]]
 isis.viewer.wicket.application.js
 
-|
+| 
 | URL of file to read any custom Javascript, relative to ``static`` package on the class path.
 
 A typical value is ``js``. This will result in this file being read from the ``static/js`` directory (because static resources such as CSS are mounted by Spring by default under ``static`` package).
@@ -127,7 +127,7 @@ name
 isis.viewer.wicket.application. +
 version
 
-|
+| 
 | The version of the application, eg 1.0, 1.1, etc.
 
 If present, then this will be shown in the footer on every page as well as on the about page.
@@ -194,7 +194,7 @@ max-parent-chain-length
 isis.viewer.wicket. +
 clear-original-destination
 
-|
+| 
 | If the end user uses a deep link to access the Wicket viewer, but is not authenticated, then this configuration property determines whether to continue through to that original destination once authenticated, or simply to go to the home page.
 
 The default behaviour is to honour the original destination requested.
@@ -204,7 +204,7 @@ The default behaviour is to honour the original destination requested.
 [[isis.viewer.wicket.credit]]
 isis.viewer.wicket.credit
 
-|
+| 
 | List of organisations or individuals to give credit to, shown as links and icons in the footer. A maximum of 3 credits can be specified.
 
 IntelliJ unfortunately does not provide IDE completion for lists of classes; YMMV.
@@ -260,7 +260,7 @@ Each Date scalar panel will use ``#getDatePattern()`` or ``#getDateTimePattern()
 isis.viewer.wicket. +
 development-utilities.enable
 
-|
+| 
 | Determines whether debug bar and other stuff influenced by ``DebugSettings#isDevelopmentUtilitiesEnabled()`` is enabled or not.
 
 By default, depends on the mode (prototyping = enabled, server = disabled). This property acts as an override.
@@ -270,7 +270,7 @@ By default, depends on the mode (prototyping = enabled, server = disabled). This
 [[isis.viewer.wicket.dialog-mode]]
 isis.viewer.wicket.dialog-mode
 
-|
+| 
 | Whether the dialog mode rendered when invoking actions on domain objects should be to use the sidebar (the default) or to use a modal dialog.
 
 This can be overridden on a case-by-case basis using ``ActionLayout#promptStyle()``.
@@ -281,7 +281,7 @@ This can be overridden on a case-by-case basis using ``ActionLayout#promptStyle(
 isis.viewer.wicket. +
 dialog-mode-for-menu
 
-|
+| 
 | Whether the dialog mode rendered when invoking actions on domain services (that is, menus) should be to use a modal dialog (the default) or to use the sidebar panel.
 
 This can be overridden on a case-by-case basis using ``ActionLayout#promptStyle()``.
@@ -291,7 +291,7 @@ This can be overridden on a case-by-case basis using ``ActionLayout#promptStyle(
 [[isis.viewer.wicket.live-reload-url]]
 isis.viewer.wicket.live-reload-url
 
-|
+| 
 | If specified, then is rendered on each page to enable live reload.
 
 Configuring live reload also requires an appropriate plugin to the web browser (eg see http://livereload.com/[livereload.com] and a mechanism to trigger changes, eg by watching ``xml`` files.
@@ -303,7 +303,7 @@ isis.viewer.wicket. +
 max-title-length-in-parented- +
 tables
 
-|
+| 
 | null
 
 
@@ -313,7 +313,7 @@ isis.viewer.wicket. +
 max-title-length-in-standalone- +
 tables
 
-|
+| 
 | null
 
 
@@ -354,7 +354,7 @@ This behaviour is enabled by default, but can be disabled using this flag.
 [[isis.viewer.wicket.prompt-style]]
 isis.viewer.wicket.prompt-style
 
-|
+| 
 | Whether to use a modal dialog for property edits and for actions associated with properties.
 
 This can be overridden on a case-by-case basis using ``@PropertyLayout#promptStyle`` and ``@ActionLayout#promptStyle``.
@@ -367,7 +367,7 @@ This behaviour is disabled by default; the viewer will use an inline prompt in t
 isis.viewer.wicket. +
 redirect-even-if-same-object
 
-|
+| 
 | Whether to redirect to a new page, even if the object being shown (after an action invocation or a property edit) is the same as the previous page.
 
 This behaviour is disabled by default; the viewer will update the existing page if it can, making for a smoother user experience. If enabled then this reinstates the pre-1.15.0 behaviour of redirecting in all cases.
@@ -387,7 +387,7 @@ cookie-key
 isis.viewer.wicket.remember-me. +
 encryption-key
 
-|
+| 
 | If the "remember me" feature is available, optionally specifies an encryption key (a complex string acting as salt to the encryption algorithm) for computing the encrypted credentials.
 
 If not set, then (in production mode) the Wicket viewer will compute a random key each time it is started. This will mean that any credentials stored between sessions will become invalid.
@@ -402,7 +402,7 @@ In prototype mode this setting is effectively ignored, because the same key will
 isis.viewer.wicket.remember-me. +
 suppress
 
-|
+| 
 | Whether the sign-in page should have a "remember me" link (the default), or if it should be suppressed.
 
 If "remember me" is available and checked, then the viewer will allow users to login based on encrypted credentials stored in a cookie. An encryption key can optionally be specified.
@@ -446,7 +446,7 @@ By default this is enabled, in other words Wicket tags are stripped. Please be a
 isis.viewer.wicket. +
 suppress-password-reset
 
-|
+| 
 | Whether to suppress the password reset link on the sign-in page.
 
 Although this is disabled by default (in other words the 'reset password' link is not suppressed), note that in addition the application must provide an implementation of the ``UserRegistrationService`` as well as a configured ``EmailNotificationService`` (same conditions as for the ``#isSuppressSignUp()`` sign-up link).
@@ -457,7 +457,7 @@ Although this is disabled by default (in other words the 'reset password' link i
 isis.viewer.wicket. +
 suppress-sign-up
 
-|
+| 
 | Whether to suppress the sign-up link on the sign-in page.
 
 Although this is disabled by default (in other words the sign-up link is not suppressed), note that in addition the application must provide an implementation of the ``UserRegistrationService`` as well as a configured ``EmailNotificationService`` (same conditions as for the ``#isSuppressPasswordReset()`` password reset link).
@@ -467,7 +467,7 @@ Although this is disabled by default (in other words the sign-up link is not sup
 [[isis.viewer.wicket.themes.enabled]]
 isis.viewer.wicket.themes.enabled
 
-|
+| 
 | A comma separated list of enabled theme names, as defined by https://bootswatch.com.
 
 
@@ -496,7 +496,7 @@ IsisWicketThemeSupportDefault
 isis.viewer.wicket.themes. +
 show-chooser
 
-|
+| 
 | Whether the theme chooser widget should be available in the footer.
 
 
@@ -526,7 +526,7 @@ This behaviour is enabled by default.
 [[isis.viewer.wicket.welcome.text]]
 isis.viewer.wicket.welcome.text
 
-|
+| 
 | Text to be displayed on the application’s home page, used as a fallback if welcome.file is not specified. If a @HomePage action exists, then that will take precedence.
 
 
@@ -535,7 +535,7 @@ isis.viewer.wicket.welcome.text
 isis.viewer.wicket. +
 wicket-source-plugin
 
-|
+| 
 | Whether the Wicket source plugin should be enabled; if so, the markup includes links to the Wicket source.
 
 This behaviour is disabled by default. Please be aware that enabloing it can substantially impact performance.
diff --git a/core/config/src/main/adoc/modules/config/pages/sections/resteasy.adoc b/core/config/src/main/adoc/modules/config/pages/sections/resteasy.adoc
index a48bab9..2995e3c 100644
--- a/core/config/src/main/adoc/modules/config/pages/sections/resteasy.adoc
+++ b/core/config/src/main/adoc/modules/config/pages/sections/resteasy.adoc
@@ -15,24 +15,15 @@ include::../section-hooks/resteasy~pre.adoc[]
 [[resteasy.as-map]]
 resteasy.as-map
 
-|
+| 
 | null
 
 
 |
-[[resteasy.authentication.strategy-class-name]]
-resteasy.authentication. +
-strategy-class-name
-
-|
-| Defaults to ``AuthenticationSessionStrategyBasicAuth``.
-
-
-|
 [[resteasy.environment]]
 resteasy.environment
 
-|
+| 
 | null
 
 
@@ -40,25 +31,15 @@ resteasy.environment
 [[resteasy.jaxrs.app.registration]]
 resteasy.jaxrs.app.registration
 
-|
+| 
 | How the implementation of the JAX-RS application is discovered.
 
 
 |
-[[resteasy.jaxrs.default-path]]
-resteasy.jaxrs.default-path
-
-|  /restful
-| The path at which the RO viewer should be mounted.
-
-Note that this is used rather than ``prefix`` because there is _NO_ implementation of ``Application``, so we rely on it being automatically created.
-
-
-|
 [[resteasy.jaxrs.defaultPath]]
 resteasy.jaxrs.defaultPath
 
-|
+| 
 | The path at which the RO viewer should be mounted.
 
 
@@ -66,7 +47,7 @@ resteasy.jaxrs.defaultPath
 [[resteasy.resteasy-settings]]
 resteasy.resteasy-settings
 
-|
+| 
 | null
 
 
diff --git a/core/config/src/main/java/org/apache/isis/core/config/IsisConfiguration.java b/core/config/src/main/java/org/apache/isis/core/config/IsisConfiguration.java
index 99032e3..ceaf342 100644
--- a/core/config/src/main/java/org/apache/isis/core/config/IsisConfiguration.java
+++ b/core/config/src/main/java/org/apache/isis/core/config/IsisConfiguration.java
@@ -39,6 +39,7 @@ import static java.lang.annotation.ElementType.METHOD;
 import static java.lang.annotation.ElementType.PARAMETER;
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
+import javax.activation.DataSource;
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.validation.Constraint;
@@ -58,7 +59,7 @@ import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.LabelPosition;
 import org.apache.isis.applib.annotation.PromptStyle;
 import org.apache.isis.applib.services.audit.AuditerService;
-import org.apache.isis.applib.services.command.CommandWithDto;
+import org.apache.isis.applib.services.command.CommandService;
 import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.publish.PublishedObjects;
@@ -503,8 +504,14 @@ public class IsisConfiguration {
                      *         If set to any other subtype, then an event <i>is</i> sent.
                      *     </li>
                      * </ul>
+                     *
+                     * <p>
+                     *     The default is <tt>false</tt>, because otherwise the mere presence of <tt>@DomainObjectLayout</tt>
+                     *     (perhaps for some attribute other than this one) will cause any imperative <code>cssClass()</code>
+                     *     method to be ignored.
+                     * </p>
                      */
-                    private boolean postForDefault = true;
+                    private boolean postForDefault = false;
                 }
 
                 private final IconUiEvent iconUiEvent = new IconUiEvent();
@@ -538,8 +545,14 @@ public class IsisConfiguration {
                      *         If set to any other subtype, then an event <i>is</i> sent.
                      *     </li>
                      * </ul>
+                     *
+                     * <p>
+                     *     The default is <tt>false</tt>, because otherwise the mere presence of <tt>@DomainObjectLayout</tt>
+                     *     (perhaps for some attribute other than this one) will cause any imperative <code>iconName()</code>
+                     *     method to be ignored.
+                     * </p>
                      */
-                    private boolean postForDefault = true;
+                    private boolean postForDefault = false;
                 }
 
                 private final LayoutUiEvent layoutUiEvent = new LayoutUiEvent();
@@ -578,8 +591,14 @@ public class IsisConfiguration {
                      *         If set to any other subtype, then an event <i>is</i> sent.
                      *     </li>
                      * </ul>
+                     *
+                     * <p>
+                     *     The default is <tt>false</tt>, because otherwise the mere presence of <tt>@DomainObjectLayout</tt>
+                     *     (perhaps for some attribute other than this one) will cause any imperative <code>layout()</code>
+                     *     method to be ignored.
+                     * </p>
                      */
-                    private boolean postForDefault = true;
+                    private boolean postForDefault = false;
                 }
 
                 private final TitleUiEvent titleUiEvent = new TitleUiEvent();
@@ -613,8 +632,14 @@ public class IsisConfiguration {
                      *         If set to any other subtype, then an event <i>is</i> sent.
                      *     </li>
                      * </ul>
+                     *
+                     * <p>
+                     *     The default is <tt>false</tt>, because otherwise the mere presence of <tt>@DomainObjectLayout</tt>
+                     *     (perhaps for some attribute other than this one) will cause any imperative <code>title()</code>
+                     *     method to be ignored.
+                     * </p>
                      */
-                    private boolean postForDefault = true;
+                    private boolean postForDefault = false;
                 }
             }
 
@@ -625,16 +650,9 @@ public class IsisConfiguration {
                 /**
                  * The default for whether action invocations should be reified as a
                  * {@link org.apache.isis.applib.services.command.Command} using the
-                 * {@link org.apache.isis.applib.services.command.spi.CommandService}, possibly so that the actual
-                 * execution of the action can be deferred until later (background execution) or replayed against a
-                 * copy of the system.
-                 *
-                 * <p>
-                 *     In particular, the {@link CommandWithDto} implementation
-                 *     of {@link org.apache.isis.applib.services.command.Command} represents the action invocation
-                 *     memento (obtained using {@link CommandWithDto#asDto()}) as a
-                 *     {@link org.apache.isis.schema.cmd.v2.CommandDto}.
-                 * </p>
+                 * {@link CommandService},
+                 * either for auditing or for replayed against a secondary
+                 * system, eg for regression testing.
                  *
                  * <p>
                  *  This setting can be overridden on a case-by-case basis using
@@ -812,20 +830,13 @@ public class IsisConfiguration {
                 /**
                  * The default for whether property edits should be reified as a
                  * {@link org.apache.isis.applib.services.command.Command} using the
-                 * {@link org.apache.isis.applib.services.command.spi.CommandService}, possibly so that the actual
-                 * execution of the property edit can be deferred until later (background execution) or replayed
-                 * against a copy of the system.
-                 *
-                 * <p>
-                 *     In particular, the {@link CommandWithDto} implementation
-                 *     of {@link org.apache.isis.applib.services.command.Command} represents the action invocation
-                 *     memento (obtained using {@link CommandWithDto#asDto()}) as a
-                 *     {@link org.apache.isis.schema.cmd.v2.CommandDto}.
-                 * </p>
+                 * {@link CommandService},
+                 * for example for auditing, or to be replayed against a
+                 * secondary system, for regression testing.
                  *
                  * <p>
                  *  This setting can be overridden on a case-by-case basis using
-                 *  {@link org.apache.isis.applib.annotation.Action#command()}.
+                 *  {@link org.apache.isis.applib.annotation.Property#command()}.
                  * </p>
                  */
                 private CommandPropertiesConfiguration command = CommandPropertiesConfiguration.NONE;
@@ -1463,7 +1474,7 @@ public class IsisConfiguration {
                 /**
                  * If an email fails to send, whether to propagate the exception (meaning that potentially the end-user
                  * might see the exception), or whether instead to just indicate failure through the return value of
-                 * the method ({@link org.apache.isis.applib.services.email.EmailService#send(List, List, List, String, String, DataSource...))
+                 * the method ({@link org.apache.isis.applib.services.email.EmailService#send(List, List, List, String, String, DataSource...)}
                  * that's being called.
                  */
                 private boolean throwExceptionOnFail = true;
@@ -2034,7 +2045,7 @@ public class IsisConfiguration {
             /**
              * The base path at which the Wicket viewer is mounted.
              */
-            @javax.validation.constraints.Pattern(regexp="^[/].*[/]$") @NotNull @NotEmpty
+            @javax.validation.constraints.Pattern(regexp="^[/](.*[/]|)$") @NotNull @NotEmpty
             private String basePath = "/wicket/";
 
             /**
@@ -3034,7 +3045,75 @@ public class IsisConfiguration {
              */
             private List<String> exposedHeaders = listOf("Authorization");
         }
+
+        private final Quartz quartz = new Quartz();
+        @Data
+        public static class Quartz {
+        }
+
+        private final CommandReplay commandReplay = new CommandReplay();
+        @Data
+        public static class CommandReplay {
+
+            private final Primary primary = new Primary();
+            @Data
+            public static class Primary {
+                private Optional<String> baseUrl;               
+                private Optional<String> user;               
+                private Optional<String> password;               
+                private Optional<String> baseUrlEndUser;               
+                private Integer batchSize = 10;               
+            }
+            
+            private final Secondary secondary = new Secondary();
+            @Data
+            public static class Secondary {
+                
+                private final QuartzSession quartzSession = new QuartzSession();
+                @Data
+                public static class QuartzSession {
+                    /**
+                     * The user that runs the replay session secondary.
+                     */
+                    private String user = "isisModuleExtCommandReplaySecondaryUser";
+                    private List<String> roles = listOf("isisModuleExtCommandReplaySecondaryRole");
+                }
+                
+                private final QuartzReplicateAndReplayJob quartzReplicateAndReplayJob = new QuartzReplicateAndReplayJob();
+                @Data
+                public static class QuartzReplicateAndReplayJob {
+                    /**
+                     * Number of milliseconds before starting the job.
+                     */
+                    private long startDelay = 15000;
+                    /**
+                     * Number of milliseconds before running again.
+                     */
+                    private long repeatInterval = 10000;
+                }
+
+                private final Analyser analyser = new Analyser();
+                @Data
+                public static class Analyser {
+                    private final Result result = new Result();
+                    @Data
+                    public static class Result {
+                        private boolean enabled = true;
+                    }
+                    private final Exception exception = new Exception();
+                    @Data
+                    public static class Exception {
+                        private boolean enabled = true;
+                    }
+
+                }
+
+            }
+            
+            
+        }
         
+
     }
 
     private static List<String> listOf(final String ...values) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotation.java
index 8b14832..a643dab 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotation.java
@@ -21,8 +21,6 @@ package org.apache.isis.core.metamodel.facets.actions.action.command;
 import java.util.Optional;
 
 import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.CommandPersistence;
 import org.apache.isis.applib.annotation.CommandReification;
 import org.apache.isis.applib.services.command.CommandDtoProcessor;
 import org.apache.isis.applib.services.inject.ServiceInjector;
@@ -48,14 +46,11 @@ public class CommandFacetForActionAnnotation extends CommandFacetAbstract {
                 .map(action -> {
 
                     CommandReification command = action.command();
-                    CommandPersistence persistence = action.commandPersistence();
-                    final CommandExecuteIn executeIn = action.commandExecuteIn();
                     final Class<? extends CommandDtoProcessor> processorClass = action.commandDtoProcessor();
                     final CommandDtoProcessor processor = newProcessorElseNull(processorClass);
 
                     if(processor != null) {
                         command = CommandReification.ENABLED;
-                        persistence = CommandPersistence.PERSISTED;
                     }
 
                     switch (command) {
@@ -71,13 +66,13 @@ public class CommandFacetForActionAnnotation extends CommandFacetAbstract {
                             // else fall through
                         default:
                             return (CommandFacet)new CommandFacetForActionAnnotationAsConfigured(
-                                    persistence, executeIn, Enablement.ENABLED, holder, servicesInjector);
+                                    holder, servicesInjector);
                         }
                     case DISABLED:
                         return null;
                     case ENABLED:
                         return new CommandFacetForActionAnnotation(
-                                persistence, executeIn, Enablement.ENABLED, processor, holder, servicesInjector);
+                                processor, holder, servicesInjector);
                     default:
                     }
                     throw new IllegalStateException("command '" + command + "' not recognised");
@@ -110,13 +105,10 @@ public class CommandFacetForActionAnnotation extends CommandFacetAbstract {
     }
 
     CommandFacetForActionAnnotation(
-            final CommandPersistence persistence,
-            final CommandExecuteIn executeIn,
-            final Enablement enablement,
             final CommandDtoProcessor processor,
             final FacetHolder holder,
             final ServiceInjector servicesInjector) {
-        super(persistence, executeIn, enablement, processor, holder, servicesInjector);
+        super(processor, holder, servicesInjector);
     }
 
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotationAsConfigured.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotationAsConfigured.java
index 9c89fd6..5719d7d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotationAsConfigured.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotationAsConfigured.java
@@ -18,21 +18,15 @@
  */
 package org.apache.isis.core.metamodel.facets.actions.action.command;
 
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.CommandPersistence;
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 
 public class CommandFacetForActionAnnotationAsConfigured extends CommandFacetForActionAnnotation {
 
     CommandFacetForActionAnnotationAsConfigured(
-            final CommandPersistence persistence,
-            final CommandExecuteIn executeIn,
-            final Enablement enablement,
             final FacetHolder holder,
             final ServiceInjector servicesInjector) {
-        super(persistence, executeIn, enablement, null,
-                holder, servicesInjector);
+        super(null, holder, servicesInjector);
     }
 
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetFromConfiguration.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetFromConfiguration.java
index 3103d57..09c49ce 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetFromConfiguration.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetFromConfiguration.java
@@ -19,8 +19,6 @@
 
 package org.apache.isis.core.metamodel.facets.actions.action.command;
 
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.CommandPersistence;
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.actions.command.CommandFacet;
@@ -31,16 +29,13 @@ public class CommandFacetFromConfiguration extends CommandFacetAbstract {
     public static CommandFacet create(
             final FacetHolder holder,
             final ServiceInjector servicesInjector) {
-        return new CommandFacetFromConfiguration(CommandPersistence.PERSISTED, CommandExecuteIn.FOREGROUND, holder,
-                servicesInjector);
+        return new CommandFacetFromConfiguration(holder, servicesInjector);
     }
 
     private CommandFacetFromConfiguration(
-            final CommandPersistence persistence,
-            final CommandExecuteIn executeIn,
             final FacetHolder holder,
             final ServiceInjector servicesInjector) {
-        super(persistence, executeIn, Enablement.ENABLED, null, holder, servicesInjector);
+        super(null, holder, servicesInjector);
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
index 69182bf..2fb6960 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
@@ -35,7 +35,7 @@ import org.apache.isis.applib.events.domain.ActionDomainEvent;
 import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandContext;
-import org.apache.isis.applib.services.command.spi.CommandService;
+import org.apache.isis.applib.services.command.CommandService;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.iactn.Interaction.ActionInvocation;
 import org.apache.isis.applib.services.iactn.InteractionContext;
@@ -43,7 +43,6 @@ import org.apache.isis.applib.services.metrics.MetricsService;
 import org.apache.isis.applib.services.queryresultscache.QueryResultsCache;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.core.commons.collections.Can;
-import org.apache.isis.core.commons.exceptions.IsisException;
 import org.apache.isis.core.commons.internal.assertions._Assert;
 import org.apache.isis.core.commons.internal.base._Casts;
 import org.apache.isis.core.commons.internal.base._Strings;
@@ -159,86 +158,68 @@ implements ImperativeFacet {
         
         // similar code in PropertySetterOrClearFacetFDEA
         
-        final CommandContext commandContext = getCommandContext();
-        final Command command = commandContext.getCommand();
+        val commandContext = getCommandContext();
+        val command = commandContext.getCommand();
 
 
-        final InteractionContext interactionContext = getInteractionContext();
-        final Interaction interaction = interactionContext.getInteraction();
+        val interactionContext = getInteractionContext();
+        val interaction = interactionContext.getInteraction();
 
-        final String actionId = owningAction.getIdentifier().toClassAndNameIdentityString();
+        val actionId = owningAction.getIdentifier().toClassAndNameIdentityString();
 
-        final ManagedObject returnedAdapter;
-        if( command.getExecutor() == Command.Executor.USER &&
-                command.getExecuteIn() == org.apache.isis.applib.annotation.CommandExecuteIn.BACKGROUND) {
 
-            // deal with background commands
+        val targetAdapter = head.getTarget();
+        val mixedInAdapter = head.getMixedIn().orElse(null);
 
-            // persist command so can it can subsequently be invoked in the 'background'
-            final CommandService commandService = getCommandService();
-            if (!commandService.persistIfPossible(command)) {
-                throw new IsisException(String.format(
-                        "Unable to persist command for action '%s'; CommandService does not support persistent commands ",
-                        actionId));
-            }
-            returnedAdapter = getObjectManager().adapt(command);
-
-        } else {
-            // otherwise, go ahead and execute action in the 'foreground'
-            
-            val targetAdapter = head.getTarget();
-            val mixedInAdapter = head.getMixedIn().orElse(null);
+        val targetPojo = UnwrapUtil.single(targetAdapter);
 
-            final Object targetPojo = UnwrapUtil.single(targetAdapter);
+        val argumentPojos = argumentAdapters.stream()
+                .map(UnwrapUtil::single)
+                .collect(_Lists.toUnmodifiable());
 
-            final List<Object> argumentPojos = argumentAdapters.stream()
-                    .map(UnwrapUtil::single)
-                    .collect(_Lists.toUnmodifiable());
+        val targetMemberName = targetNameFor(owningAction, mixedInAdapter);
+        val targetClass = CommandUtil.targetClassNameFor(targetAdapter);
 
-            final String targetMember = targetNameFor(owningAction, mixedInAdapter);
-            final String targetClass = CommandUtil.targetClassNameFor(targetAdapter);
+        val actionInvocation =
+                new Interaction.ActionInvocation(
+                        interaction, actionId, targetPojo, argumentPojos, targetMemberName,
+                        targetClass);
+        final Interaction.MemberExecutor<Interaction.ActionInvocation> memberExecutor =
+                new DomainEventMemberExecutor(
+                        argumentAdapters, targetAdapter, command, owningAction,
+                        targetAdapter, mixedInAdapter, actionInvocation);
 
-            final Interaction.ActionInvocation execution =
-                    new Interaction.ActionInvocation(
-                            interaction, actionId, targetPojo, argumentPojos, targetMember,
-                            targetClass);
-            final Interaction.MemberExecutor<Interaction.ActionInvocation> callable =
-                    new DomainEventMemberExecutor(
-                            argumentAdapters, targetAdapter, command, owningAction,
-                            targetAdapter, mixedInAdapter, execution);
+        // sets up startedAt and completedAt on the execution, also manages the execution call graph
+        interaction.execute(memberExecutor, actionInvocation, getClockService(), getMetricsService());
 
-            // sets up startedAt and completedAt on the execution, also manages the execution call graph
-            interaction.execute(callable, execution, getClockService(), getMetricsService());
+        // handle any exceptions
+        final Interaction.Execution<ActionInvocationDto, ?> priorExecution =
+                _Casts.uncheckedCast(interaction.getPriorExecution());
 
-            // handle any exceptions
-            final Interaction.Execution<ActionInvocationDto, ?> priorExecution =
-                    _Casts.uncheckedCast(interaction.getPriorExecution());
+        val executionExceptionIfAny = priorExecution.getThrew();
 
-            final Exception executionExceptionIfAny = priorExecution.getThrew();
+        // TODO: should also sync DTO's 'threw' attribute here...?
 
-            // TODO: should also sync DTO's 'threw' attribute here...?
-
-            if(executionExceptionIfAny != null) {
-                throw executionExceptionIfAny instanceof RuntimeException
-                ? ((RuntimeException)executionExceptionIfAny)
-                        : new RuntimeException(executionExceptionIfAny);
-            }
+        if(executionExceptionIfAny != null) {
+            throw executionExceptionIfAny instanceof RuntimeException
+            ? ((RuntimeException)executionExceptionIfAny)
+                    : new RuntimeException(executionExceptionIfAny);
+        }
 
-            final Object returnedPojo = priorExecution.getReturned();
-            returnedAdapter = getObjectManager().adapt(returnedPojo);
+        val returnedPojo = priorExecution.getReturned();
+        val returnedAdapter = getObjectManager().adapt(returnedPojo);
 
-            // sync DTO with result
-            getInteractionDtoServiceInternal()
-            .updateResult(priorExecution.getDto(), owningAction, returnedPojo);
+        // sync DTO with result
+        getInteractionDtoServiceInternal()
+        .updateResult(priorExecution.getDto(), owningAction, returnedPojo);
 
-            // update Command (if required)
-            setCommandResultIfEntity(command, returnedAdapter);
+        // update Command (if required)
+        setCommandResultIfEntity(command, returnedAdapter);
 
-            // publish (if not a contributed association, query-only mixin)
-            final PublishedActionFacet publishedActionFacet = getIdentified().getFacet(PublishedActionFacet.class);
-            if (publishedActionFacet != null) {
-                getPublishingServiceInternal().publishAction(priorExecution);
-            }
+        // publish (if not a contributed association, query-only mixin)
+        val publishedActionFacet = getIdentified().getFacet(PublishedActionFacet.class);
+        if (publishedActionFacet != null) {
+            getPublishingServiceInternal().publishAction(priorExecution);
         }
 
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/CommandUtil.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/CommandUtil.java
index 00509f0..f80fd79 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/CommandUtil.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/CommandUtil.java
@@ -32,6 +32,7 @@ import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 
 import lombok.val;
 
@@ -58,6 +59,31 @@ public class CommandUtil {
         return objectMember.getIdentifier().toClassAndNameIdentityString();
     }
 
+    public static String logicalMemberIdentifierFor(final ObjectMember objectMember) {
+        if(objectMember instanceof ObjectAction) {
+            return logicalMemberIdentifierFor((ObjectAction)objectMember);
+        }
+        if(objectMember instanceof OneToOneAssociation) {
+            return logicalMemberIdentifierFor((OneToOneAssociation)objectMember);
+        }
+        throw new IllegalArgumentException(objectMember.getClass() + " is not supported");
+    }
+
+    public static String logicalMemberIdentifierFor(final ObjectAction objectAction) {
+        return logicalMemberIdentifierFor(objectAction.getOnType(), objectAction);
+    }
+
+    public static String logicalMemberIdentifierFor(final OneToOneAssociation otoa) {
+        return logicalMemberIdentifierFor(otoa.getOnType(), otoa);
+    }
+
+    private static String logicalMemberIdentifierFor(
+            final ObjectSpecification onType, final ObjectMember objectMember) {
+        final String objectType = onType.getSpecId().asString();
+        final String localId = objectMember.getIdentifier().toNameIdentityString();
+        return objectType + "#" + localId;
+    }
+
     public static String argDescriptionFor(final ManagedObject valueAdapter) {
         final StringBuilder buf = new StringBuilder();
         if(valueAdapter != null) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacet.java
index cfc278b..36af57d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacet.java
@@ -19,9 +19,6 @@
 
 package org.apache.isis.core.metamodel.facets.actions.command;
 
-import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.CommandPersistence;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandDtoProcessor;
 import org.apache.isis.core.metamodel.facetapi.Facet;
@@ -36,20 +33,5 @@ import org.apache.isis.core.metamodel.facetapi.Facet;
  */
 public interface CommandFacet extends Facet {
 
-    public CommandPersistence persistence();
-
-    public CommandExecuteIn executeIn();
-
-    /**
-     * Indicates that the action to which this {@link Facet} is
-     * attached should <i>not</i> be treated as an action.
-     *
-     * <p>
-     * Exists to allow implementations that configure all actions to be treated as
-     * commands, but which can then be disabled for selected actions (eg using
-     * {@link Action#command()}).
-     */
-    public boolean isDisabled();
-
     public CommandDtoProcessor getProcessor();
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacetAbstract.java
index d51e342..8f53327 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacetAbstract.java
@@ -21,8 +21,6 @@ package org.apache.isis.core.metamodel.facets.actions.command;
 
 import java.util.Map;
 
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.CommandPersistence;
 import org.apache.isis.applib.services.command.CommandDtoProcessor;
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.core.metamodel.facetapi.Facet;
@@ -35,32 +33,14 @@ public abstract class CommandFacetAbstract extends FacetAbstract implements Comm
         return CommandFacet.class;
     }
 
-    public enum Enablement {
-        DISABLED,
-        ENABLED;
-
-        public static Enablement isDisabled(boolean disabled) {
-            return disabled ? DISABLED: ENABLED;
-        }
-    }
-
-    private final CommandPersistence persistence;
-    private final CommandExecuteIn executeIn;
-    private final Enablement enablement;
     private final CommandDtoProcessor processor;
 
     public CommandFacetAbstract(
-            final CommandPersistence persistence,
-            final CommandExecuteIn executeIn,
-            final Enablement enablement,
             final CommandDtoProcessor processor,
             final FacetHolder holder,
             final ServiceInjector servicesInjector) {
         super(type(), holder);
         inject(processor, servicesInjector);
-        this.persistence = persistence;
-        this.executeIn = executeIn;
-        this.enablement = enablement;
         this.processor = processor;
     }
 
@@ -73,21 +53,6 @@ public abstract class CommandFacetAbstract extends FacetAbstract implements Comm
     }
 
     @Override
-    public CommandPersistence persistence() {
-        return this.persistence;
-    }
-
-    @Override
-    public CommandExecuteIn executeIn() {
-        return executeIn;
-    }
-
-    @Override
-    public boolean isDisabled() {
-        return this.enablement == Enablement.DISABLED;
-    }
-
-    @Override
     public CommandDtoProcessor getProcessor() {
         return processor;
     }
@@ -115,9 +80,6 @@ public abstract class CommandFacetAbstract extends FacetAbstract implements Comm
 
     @Override public void appendAttributesTo(final Map<String, Object> attributeMap) {
         super.appendAttributesTo(attributeMap);
-        attributeMap.put("executeIn", executeIn);
-        attributeMap.put("persistence", persistence);
-        attributeMap.put("disabled", isDisabled());
         attributeMap.put("dtoProcessor", processor);
     }
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
index cb12ad0..88199a9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
@@ -248,7 +248,7 @@ implements MetaModelRefiner {
 
         // check for @Property(command=...)
         val commandFacet = CommandFacetForPropertyAnnotation
-                .create(propertyIfAny, getConfiguration(), facetHolder, getServiceInjector());
+                .create(propertyIfAny, getConfiguration(), facetHolder,  getServiceInjector());
 
         super.addFacet(commandFacet);
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotation.java
index 8a551cb..e80a21c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotation.java
@@ -20,8 +20,6 @@ package org.apache.isis.core.metamodel.facets.properties.property.command;
 
 import java.util.Optional;
 
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.CommandPersistence;
 import org.apache.isis.applib.annotation.CommandReification;
 import org.apache.isis.applib.annotation.Property;
 import org.apache.isis.applib.services.command.CommandDtoProcessor;
@@ -32,6 +30,9 @@ import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.actions.action.command.CommandFacetFromConfiguration;
 import org.apache.isis.core.metamodel.facets.actions.command.CommandFacet;
 import org.apache.isis.core.metamodel.facets.actions.command.CommandFacetAbstract;
+import org.apache.isis.core.metamodel.facets.object.audit.AuditableFacetAbstract;
+
+import lombok.val;
 
 public class CommandFacetForPropertyAnnotation extends CommandFacetAbstract {
 
@@ -46,33 +47,30 @@ public class CommandFacetForPropertyAnnotation extends CommandFacetAbstract {
         return propertyIfAny
                 .filter(property -> property.command() != CommandReification.NOT_SPECIFIED)
                 .map(property -> {
-                    CommandReification command = property.command();
-                    final CommandPersistence commandPersistence = property.commandPersistence();
-                    final CommandExecuteIn commandExecuteIn = property.commandExecuteIn();
+                    CommandReification commandReification = property.command();
 
                     final Class<? extends CommandDtoProcessor> processorClass =
-                            property != null ? property.commandDtoProcessor() : null;
-                            final CommandDtoProcessor processor = newProcessorElseNull(processorClass);
+                            property.commandDtoProcessor();
+                    final CommandDtoProcessor processor = newProcessorElseNull(processorClass);
 
-                            if(processor != null) {
-                                command = CommandReification.ENABLED;
-                            }
-                            switch (command) {
-                            case AS_CONFIGURED:
-                                switch (setting) {
-                                case NONE:
-                                    return null;
-                                default:
-                                    return (CommandFacet)new CommandFacetForPropertyAnnotationAsConfigured(commandPersistence,
-                                            commandExecuteIn, Enablement.ENABLED, holder, servicesInjector);
-                                }
-                            case DISABLED:
-                                return null;
-                            case ENABLED:
-                                return new CommandFacetForPropertyAnnotation(commandPersistence, commandExecuteIn, Enablement.ENABLED, holder, processor, servicesInjector);
-                            default:
-                            }
-                            throw new IllegalStateException("command '" + command + "' not recognised");
+                    if(processor != null) {
+                        commandReification = CommandReification.ENABLED;
+                    }
+                    switch (commandReification) {
+                    case AS_CONFIGURED:
+                        switch (setting) {
+                        case NONE:
+                            return null;
+                        default:
+                            return (CommandFacet)new CommandFacetForPropertyAnnotationAsConfigured(holder, servicesInjector);
+                        }
+                    case DISABLED:
+                        return null;
+                    case ENABLED:
+                        return new CommandFacetForPropertyAnnotation(holder, processor, servicesInjector);
+                    default:
+                    }
+                    throw new IllegalStateException("command '" + commandReification + "' not recognised");
                 })
                 .orElseGet(() -> {
                     switch (setting) {
@@ -86,13 +84,10 @@ public class CommandFacetForPropertyAnnotation extends CommandFacetAbstract {
 
 
     CommandFacetForPropertyAnnotation(
-            final CommandPersistence persistence,
-            final CommandExecuteIn executeIn,
-            final Enablement enablement,
             final FacetHolder holder,
             final CommandDtoProcessor processor,
             final ServiceInjector servicesInjector) {
-        super(persistence, executeIn, enablement, processor, holder, servicesInjector);
+        super(processor, holder, servicesInjector);
     }
 
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotationAsConfigured.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotationAsConfigured.java
index 0e5cc23..86931de 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotationAsConfigured.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotationAsConfigured.java
@@ -18,19 +18,14 @@
  */
 package org.apache.isis.core.metamodel.facets.properties.property.command;
 
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.CommandPersistence;
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 
 public class CommandFacetForPropertyAnnotationAsConfigured extends CommandFacetForPropertyAnnotation {
 
     CommandFacetForPropertyAnnotationAsConfigured(
-            final CommandPersistence persistence,
-            final CommandExecuteIn executeIn,
-            final Enablement enablement,
             final FacetHolder holder, final ServiceInjector servicesInjector) {
-        super(persistence, executeIn, enablement, holder, null, servicesInjector);
+        super(holder, null, servicesInjector);
     }
 
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
index 66458d8..ae7e96e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
@@ -27,11 +27,10 @@ import org.apache.isis.applib.events.domain.PropertyDomainEvent;
 import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandContext;
-import org.apache.isis.applib.services.command.spi.CommandService;
+import org.apache.isis.applib.services.command.CommandService;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.iactn.InteractionContext;
 import org.apache.isis.applib.services.metrics.MetricsService;
-import org.apache.isis.core.commons.exceptions.IsisException;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
@@ -49,7 +48,6 @@ import org.apache.isis.core.metamodel.services.publishing.PublisherDispatchServi
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ManagedObjects.UnwrapUtil;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
-import org.apache.isis.schema.ixn.v2.PropertyEditDto;
 
 import static org.apache.isis.core.commons.internal.base._Casts.uncheckedCast;
 
@@ -180,41 +178,21 @@ extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>> {
             return head.getTarget();
         }
 
-        final InteractionContext interactionContext = getInteractionContext();
-        final Interaction interaction = interactionContext.getInteraction();
+        val interactionContext = getInteractionContext();
+        val interaction = interactionContext.getInteraction();
 
-        final String propertyId = owningProperty.getIdentifier().toClassAndNameIdentityString();
+        val propertyId = owningProperty.getIdentifier().toClassAndNameIdentityString();
 
-        if( command.getExecutor() == Command.Executor.USER
-                && command.getExecuteIn() == org.apache.isis.applib.annotation.CommandExecuteIn.BACKGROUND) {
+        val targetManagedObject = head.getTarget();
+        val target = UnwrapUtil.single(targetManagedObject);
+        val argValue = UnwrapUtil.single(newValueAdapter);
 
-            // deal with background commands
+        val targetMemberName = CommandUtil.targetMemberNameFor(owningProperty);
+        val targetClass = CommandUtil.targetClassNameFor(targetManagedObject);
 
-            // persist command so can it can subsequently be invoked in the 'background'
-            final CommandService commandService = getCommandService();
-            if (!commandService.persistIfPossible(command)) {
-                throw new IsisException(String.format(
-                        "Unable to persist command for property '%s'; CommandService does not support persistent commands ",
-                        propertyId));
-            }
-
-            return head.getTarget();
-
-        } else {
-
-            val targetAdapter = head.getTarget();
-            final Object target = UnwrapUtil.single(targetAdapter);
-            final Object argValue = UnwrapUtil.single(newValueAdapter);
-
-            final String targetMember = CommandUtil.targetMemberNameFor(owningProperty);
-            final String targetClass = CommandUtil.targetClassNameFor(targetAdapter);
-
-            final Interaction.PropertyEdit execution =
-                    new Interaction.PropertyEdit(interaction, propertyId, target, argValue, targetMember, targetClass);
-            final Interaction.MemberExecutor<Interaction.PropertyEdit> executor =
-                    new Interaction.MemberExecutor<Interaction.PropertyEdit>() {
-                @Override
-                public Object execute(final Interaction.PropertyEdit currentExecution) {
+        val propertyEdit = new Interaction.PropertyEdit(interaction, propertyId, target, argValue, targetMemberName, targetClass);
+        final Interaction.MemberExecutor<Interaction.PropertyEdit> executor =
+                currentExecution -> {
 
                     // TODO: REVIEW - is this safe to do?
                     ManagedObject newValueAdapterMutatable = newValueAdapter;
@@ -222,62 +200,62 @@ extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>> {
                     try {
 
                         // update the current execution with the DTO (memento)
-                        final PropertyEditDto editDto =
+                        val propertyEditDto =
                                 getInteractionDtoServiceInternal().asPropertyEditDto(
-                                        owningProperty, targetAdapter, newValueAdapterMutatable);
-                        currentExecution.setDto(editDto);
+                                        owningProperty, targetManagedObject, newValueAdapterMutatable);
+                        currentExecution.setDto(propertyEditDto);
 
 
                         // set the startedAt (and update command if this is the top-most member execution)
                         // (this isn't done within Interaction#execute(...) because it requires the DTO
                         // to have been set on the current execution).
-                        val startedAt = execution.start(getClockService(), getMetricsService());
+                        val startedAt = propertyEdit.start(getClockService(), getMetricsService());
                         if(command.getStartedAt() == null) {
                             command.internal().setStartedAt(startedAt);
                         }
 
                         // ... post the executing event
-                        final Object oldValue = getterFacet.getProperty(targetAdapter, interactionInitiatedBy);
-                        final Object newValue = UnwrapUtil.single(newValueAdapterMutatable);
+                        val oldValuePojo = getterFacet.getProperty(targetManagedObject, interactionInitiatedBy);
+                        val newValuePojo = UnwrapUtil.single(newValueAdapterMutatable);
 
-                        final PropertyDomainEvent<?, ?> event =
+                        val propertyDomainEvent =
                                 domainEventHelper.postEventForProperty(
                                         AbstractDomainEvent.Phase.EXECUTING,
                                         getEventType(), null,
                                         getIdentified(), head,
-                                        oldValue, newValue);
+                                        oldValuePojo, newValuePojo);
 
-                        Object newValuePossiblyUpdated = event.getNewValue();
-                        if(!Objects.equals(newValuePossiblyUpdated, newValue)) {
-                            newValueAdapterMutatable = newValuePossiblyUpdated != null
-                                    ? getObjectManager().adapt(newValuePossiblyUpdated)
+                        val newValuePojoPossiblyUpdated = propertyDomainEvent.getNewValue();
+                        if(!Objects.equals(newValuePojoPossiblyUpdated, newValuePojo)) {
+                            newValueAdapterMutatable = newValuePojoPossiblyUpdated != null
+                                    ? getObjectManager().adapt(newValuePojoPossiblyUpdated)
                                     : null;
                         }
 
                         // set event onto the execution
-                        currentExecution.setEvent(event);
+                        currentExecution.setEvent(propertyDomainEvent);
 
                         // invoke method
                         style.invoke(PropertySetterOrClearFacetForDomainEventAbstract.this, owningProperty,
-                                targetAdapter, newValueAdapterMutatable, interactionInitiatedBy);
+                                targetManagedObject, newValueAdapterMutatable, interactionInitiatedBy);
 
 
                         // reading the actual value from the target object, playing it safe...
-                        final Object actualNewValue = getterFacet.getProperty(targetAdapter, interactionInitiatedBy);
-                        if (!Objects.equals(oldValue, actualNewValue)) {
+                        val actualNewValue = getterFacet.getProperty(targetManagedObject, interactionInitiatedBy);
+                        if (!Objects.equals(oldValuePojo, actualNewValue)) {
 
                             // ... post the executed event
                             domainEventHelper.postEventForProperty(
                                     AbstractDomainEvent.Phase.EXECUTED,
-                                    getEventType(), uncheckedCast(event),
+                                    getEventType(), uncheckedCast(propertyDomainEvent),
                                     getIdentified(), head,
-                                    oldValue, actualNewValue);
+                                    oldValuePojo, actualNewValue);
                         }
 
-                        ManagedObject targetAdapterPossiblyCloned =
-                                cloneIfViewModelCloneable(targetAdapter);
+                        val targetManagedObjectPossiblyCloned =
+                                cloneIfViewModelCloneable(targetManagedObject);
 
-                        return targetAdapterPossiblyCloned.getPojo();
+                        return targetManagedObjectPossiblyCloned.getPojo();
 
                         //
                         // REVIEW: the corresponding action has a whole bunch of error handling here.
@@ -287,33 +265,30 @@ extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>> {
                     } finally {
 
                     }
-                }
-            };
+                };
 
-            // sets up startedAt and completedAt on the execution, also manages the execution call graph
-            Object targetPojo = interaction.execute(executor, execution, getClockService(), getMetricsService());
+        // sets up startedAt and completedAt on the execution, also manages the execution call graph
+        val targetPojo = interaction.execute(executor, propertyEdit, getClockService(), getMetricsService());
 
-            // handle any exceptions
-            final Interaction.Execution<?, ?> priorExecution = interaction.getPriorExecution();
+        // handle any exceptions
+        final Interaction.Execution<?, ?> priorExecution = interaction.getPriorExecution();
 
-            // TODO: should also sync DTO's 'threw' attribute here...?
+        // TODO: should also sync DTO's 'threw' attribute here...?
 
-            final Exception executionExceptionIfAny = priorExecution.getThrew();
-            if(executionExceptionIfAny != null) {
-                throw executionExceptionIfAny instanceof RuntimeException
-                ? ((RuntimeException)executionExceptionIfAny)
-                        : new RuntimeException(executionExceptionIfAny);
-            }
-
-
-            // publish (if not a contributed association, query-only mixin)
-            final PublishedPropertyFacet publishedPropertyFacet = getIdentified().getFacet(PublishedPropertyFacet.class);
-            if (publishedPropertyFacet != null) {
-                getPublishingServiceInternal().publishProperty(priorExecution);
-            }
+        val executionExceptionIfAny = priorExecution.getThrew();
+        if(executionExceptionIfAny != null) {
+            throw executionExceptionIfAny instanceof RuntimeException
+            ? ((RuntimeException)executionExceptionIfAny)
+                    : new RuntimeException(executionExceptionIfAny);
+        }
 
-            return getObjectManager().adapt(targetPojo);
+        // publish (if not a contributed association, query-only mixin)
+        val publishedPropertyFacet = getIdentified().getFacet(PublishedPropertyFacet.class);
+        if (publishedPropertyFacet != null) {
+            getPublishingServiceInternal().publishProperty(priorExecution);
         }
+
+        return getObjectManager().adapt(targetPojo);
     }
 
     private ManagedObject cloneIfViewModelCloneable(final ManagedObject adapter) {
@@ -325,8 +300,7 @@ extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>> {
         final ViewModelFacet viewModelFacet = adapter.getSpecification().getFacet(ViewModelFacet.class);
         final Object clone = viewModelFacet.clone(adapter.getPojo());
 
-        final ManagedObject clonedAdapter = getObjectManager().adapt(clone);
-        return clonedAdapter;
+        return getObjectManager().adapt(clone);
     }
 
     public <S, T> Class<? extends PropertyDomainEvent<S, T>> getEventType() {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/schema/IsisSchemaValueTypeProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/schema/IsisSchemaValueTypeProvider.java
index 01f96a3..32b9a3d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/schema/IsisSchemaValueTypeProvider.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/schema/IsisSchemaValueTypeProvider.java
@@ -33,7 +33,7 @@ import org.apache.isis.schema.common.v2.ValueType;
 import org.apache.isis.schema.ixn.v2.InteractionDto;
 
 @Component
-@Named("isisMetaModel.isisSchema.ValueTypeProvider")
+@Named("isisMetaModel.isisSchemaValueTypeProvider")
 public class IsisSchemaValueTypeProvider implements ValueTypeProvider {
     @Override
     public Collection<ValueTypeDefinition> definitions() {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureId.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureId.java
index 1ef6e8a..cd0b1e9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureId.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureId.java
@@ -454,8 +454,8 @@ public class ApplicationFeatureId implements Comparable<ApplicationFeatureId>, S
     private static final ToString<ApplicationFeatureId> toString =
             ObjectContracts.toString("type", ApplicationFeatureId::getType)
             .thenToString("packageName", ApplicationFeatureId::getPackageName)
-            .thenToStringOmmitIfAbsent("className", ApplicationFeatureId::getClassName)
-            .thenToStringOmmitIfAbsent("memberName", ApplicationFeatureId::getMemberName);
+            .thenToStringOmitIfAbsent("className", ApplicationFeatureId::getClassName)
+            .thenToStringOmitIfAbsent("memberName", ApplicationFeatureId::getMemberName);
 
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/command/CommandDtoServiceInternal.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/command/CommandDtoServiceInternal.java
index b0babce..7742c05 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/command/CommandDtoServiceInternal.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/command/CommandDtoServiceInternal.java
@@ -35,35 +35,32 @@ import org.apache.isis.schema.cmd.v2.PropertyDto;
  */
 public interface CommandDtoServiceInternal {
 
-
     /**
-     * Returns a JAXB DTO (hence convertible to XML) that represents the intention to invoke an action on a
-     * target object (or possibly many targets, for bulk actions), or to edit a property.  If an action, it can also
-     * be either mixin action or a contributed action.
+     * @return a DTO that represents the intention to invoke an action on a
+     *         target object (or possibly many targets, for bulk actions),
+     *         or to edit a property.  If an action, it be either a
+     *         mixin action or a contributed action.
      */
-    @Programmatic
     CommandDto asCommandDto(
             final List<ManagedObject> targetAdapters,
             final ObjectAction objectAction,
             final Can<ManagedObject> argAdapters);
 
     /**
-     * Returns a JAXB DTO (hence convertible to XML) that represents the intention to edit (set or clear) a property on
-     * a target (or possibly many targets, for symmetry with actions).
+     * @return a DTO that represents the intention to edit (set or clear) a
+     *         property on a target (or possibly many targets, for symmetry
+     *         with actions).
      */
-    @Programmatic
     CommandDto asCommandDto(
             final List<ManagedObject> targetAdapters,
             final OneToOneAssociation association,
             final ManagedObject valueAdapterOrNull);
 
-    @Programmatic
     void addActionArgs(
             final ObjectAction objectAction,
             final ActionDto actionDto,
             final Can<ManagedObject> argAdapters);
 
-    @Programmatic
     void addPropertyValue(
             final OneToOneAssociation property,
             final PropertyDto propertyDto,
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
index 98988ad..02d7667 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
@@ -30,7 +30,6 @@ import org.apache.isis.applib.RecoverableException;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.CommandContext;
 import org.apache.isis.core.commons.collections.Can;
 import org.apache.isis.core.commons.collections.CanVector;
 import org.apache.isis.core.commons.internal.assertions._Assert;
@@ -45,7 +44,6 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facets.FacetedMethod;
 import org.apache.isis.core.metamodel.facets.FacetedMethodParameter;
 import org.apache.isis.core.metamodel.facets.actions.action.invocation.ActionInvocationFacet;
-import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUtil;
 import org.apache.isis.core.metamodel.facets.actions.defaults.ActionDefaultsFacet;
 import org.apache.isis.core.metamodel.facets.actions.prototype.PrototypeFacet;
 import org.apache.isis.core.metamodel.facets.actions.semantics.ActionSemanticsFacet;
@@ -65,6 +63,7 @@ import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
+import org.apache.isis.schema.cmd.v2.CommandDto;
 
 import lombok.NonNull;
 import lombok.val;
@@ -381,13 +380,8 @@ implements ObjectAction {
     }
 
     /**
-     * Sets up the {@link Command}, then delegates off to
-     * {@link #executeInternal(ManagedObject, ManagedObject, List, InteractionInitiatedBy) executeInternal}
+     * Sets up the {@link Command}, then delegates to {@link #executeInternal(InteractionHead, Can, InteractionInitiatedBy)}
      * to invoke the {@link ActionInvocationFacet invocation facet}.
-     *
-     * @param mixedInAdapter - will be null for regular actions, and for mixin actions.  
-     * When a mixin action invokes its underlying mixedIn action, then will be populated 
-     * (so that the ActionDomainEvent can correctly provide the underlying mixin)
      */
     @Override
     public ManagedObject execute(
@@ -578,53 +572,34 @@ implements ObjectAction {
     }
 
     /**
-     * Internal API, called by the various implementations of {@link ObjectAction} ({@link ObjectActionDefault default},
-     * {@link ObjectActionMixedIn mixed-in} and {@link ObjectActionContributee contributee}).
+     * Internal API, called by the various implementations of
+     * {@link ObjectAction} ({@link ObjectActionDefault default} and
+     * {@link ObjectActionMixedIn mixed-in}.
      */
     public void setupCommand(
             final ManagedObject targetAdapter,
             final Can<ManagedObject> argumentAdapters) {
 
-        final CommandContext commandContext = getCommandContext();
-        final Command command = commandContext.getCommand();
-
-        _Assert.assertNotNull(command, "No command available with current thread, "
-                + "are we missing an interaction context?");
-        
-        if (command.getExecutor() != Command.Executor.USER) {
-            return;
-        }
-
-        setupCommandTarget(targetAdapter, argumentAdapters);
-        setupCommandMemberIdentifier();
-        setupCommandMementoAndExecutionContext(targetAdapter, argumentAdapters);
+        setupCommandTarget(targetAdapter);
+        setupCommandLogicalMemberIdentifier();
+        val dto = createCommandDto(targetAdapter, argumentAdapters);
+        setupCommandDtoAndExecutionContext(dto);
     }
 
-    private void setupCommandTarget(
+    private CommandDto createCommandDto(
             final ManagedObject targetAdapter,
             final Can<ManagedObject> argumentAdapters) {
 
-        final String arguments = CommandUtil.argDescriptionFor(this, argumentAdapters.toList());
-        super.setupCommandTarget(targetAdapter, arguments);
-    }
-
-    private void setupCommandMementoAndExecutionContext(
-            final ManagedObject targetAdapter,
-            final Can<ManagedObject> argumentAdapters) {
-
-        val commandDtoServiceInternal = getCommandDtoService();
         final List<ManagedObject> commandTargetAdapters =
                 commandTargetAdaptersHolder.get() != null
                 ? commandTargetAdaptersHolder.get()
                         : Collections.singletonList(targetAdapter);
 
-                val commandDto = commandDtoServiceInternal.asCommandDto(
-                        commandTargetAdapters, this, argumentAdapters);
-
-                setupCommandDtoAndExecutionContext(commandDto);
-
+        return getCommandDtoServiceInternal().asCommandDto(
+                commandTargetAdapters, this, argumentAdapters);
     }
 
+
     // -- toString
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
index 55ee3db..64caed4 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
@@ -26,7 +26,7 @@ import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandContext;
-import org.apache.isis.applib.util.schema.CommandDtoUtils;
+import org.apache.isis.core.commons.internal.assertions._Assert;
 import org.apache.isis.core.metamodel.commons.StringExtensions;
 import org.apache.isis.core.metamodel.consent.Consent;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
@@ -36,7 +36,6 @@ import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facets.FacetedMethod;
 import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUtil;
-import org.apache.isis.core.metamodel.facets.actions.command.CommandFacet;
 import org.apache.isis.core.metamodel.facets.all.describedas.DescribedAsFacet;
 import org.apache.isis.core.metamodel.facets.all.help.HelpFacet;
 import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
@@ -309,81 +308,51 @@ implements ObjectMember, MetaModelContext.Delegating, FacetHolder.Delegating {
         return getServiceRegistry().lookupServiceElseFail(CommandContext.class);
     }
 
-    protected CommandDtoServiceInternal getCommandDtoService() {
+    protected CommandDtoServiceInternal getCommandDtoServiceInternal() {
         return getServiceRegistry().lookupServiceElseFail(CommandDtoServiceInternal.class);
     }
 
     // -- command (setup)
 
-
-    protected void setupCommandTarget(final ManagedObject targetAdapter, final String arguments) {
+    protected void setupCommandTarget(final ManagedObject targetAdapter) {
         final CommandContext commandContext = getCommandContext();
         final Command command = commandContext.getCommand();
 
-        if (command.getExecutor() != Command.Executor.USER) {
-            return;
-        }
+        _Assert.assertNotNull(command, "No command available with current thread, "
+                + "are we missing an interaction context?");
 
         if(command.getTarget() != null) {
             // is set up by the outer-most action; inner actions (invoked via the WrapperFactory) must not overwrite
             return;
         }
 
-        command.internal().setTargetClass(CommandUtil.targetClassNameFor(targetAdapter));
-        command.internal().setTargetAction(CommandUtil.targetMemberNameFor(this));
-        command.internal().setArguments(arguments);
-
         final Bookmark targetBookmark = CommandUtil.bookmarkFor(targetAdapter);
         command.internal().setTarget(targetBookmark);
     }
 
-    protected void setupCommandMemberIdentifier() {
+    protected void setupCommandLogicalMemberIdentifier() {
 
-        final CommandContext commandContext = getCommandContext();
-        final Command command = commandContext.getCommand();
-
-        if (command.getExecutor() != Command.Executor.USER) {
-            return;
-        }
+        val command = getCommandContext().getCommand();
 
-        if (command.getMemberIdentifier() != null) {
+        if (command.getLogicalMemberIdentifier() != null) {
             // any contributed/mixin actions will fire after the main action
             // the guard here prevents them from trashing the command's memberIdentifier
             return;
         }
 
-        command.internal().setMemberIdentifier(CommandUtil.memberIdentifierFor(this));
+        command.internal().setLogicalMemberIdentifier(CommandUtil.logicalMemberIdentifierFor(this));
     }
 
     protected void setupCommandDtoAndExecutionContext(final CommandDto dto) {
-        final CommandContext commandContext = getCommandContext();
-        final Command command = commandContext.getCommand();
-
-        if (command.getExecutor() != Command.Executor.USER) {
-            return;
-        }
+        val command = getCommandContext().getCommand();
 
-        if (command.getMemento() != null) {
+        if (command.getCommandDto() != null) {
             // guard here to prevent subsequent contributed/mixin actions from
             // trampling over the command's memento and execution context
             return;
         }
 
-        // memento
-
-        final String mementoXml = CommandDtoUtils.toXml(dto);
-        command.internal().setMemento(mementoXml);
-
-        // copy over the command execution 'context' (if available)
-        final CommandFacet commandFacet = getFacetHolder().getFacet(CommandFacet.class);
-        if(commandFacet != null && !commandFacet.isDisabled()) {
-            //command.internal().setExecuteIn(commandFacet.executeIn());
-            command.internal().setPersistence(commandFacet.persistence());
-        } else {
-            // if no facet, assume do want to execute right now, but only persist (eventually) if hinted.
-            //command.internal().setExecuteIn(org.apache.isis.applib.annotation.CommandExecuteIn.FOREGROUND);
-            command.internal().setPersistence(org.apache.isis.applib.annotation.CommandPersistence.IF_HINTED);
-        }
+        command.internal().setCommandDto(dto);
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationDefault.java
index f94919f..272a9c7 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationDefault.java
@@ -31,7 +31,6 @@ import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.consent.InteractionResult;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facets.FacetedMethod;
-import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUtil;
 import org.apache.isis.core.metamodel.facets.objectvalue.mandatory.MandatoryFacet;
 import org.apache.isis.core.metamodel.facets.param.autocomplete.MinLengthUtil;
 import org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
@@ -48,7 +47,6 @@ import org.apache.isis.core.metamodel.interactions.PropertyVisibilityContext;
 import org.apache.isis.core.metamodel.interactions.UsabilityContext;
 import org.apache.isis.core.metamodel.interactions.ValidityContext;
 import org.apache.isis.core.metamodel.interactions.VisibilityContext;
-import org.apache.isis.core.metamodel.services.command.CommandDtoServiceInternal;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ManagedObjects.EntityUtil;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -301,37 +299,15 @@ implements OneToOneAssociation {
             final ManagedObject targetAdapter,
             final ManagedObject valueAdapterOrNull) {
 
-        val currentExecutor = getCommandContext()
-                .getCurrentExecutor()
-                .orElse(Command.Executor.OTHER);
-
-        if (currentExecutor != Command.Executor.USER) {
-            return;
-        }
-
-        setupCommandTarget(targetAdapter, valueAdapterOrNull);
-        setupCommandMemberIdentifier();
-        setupCommandMementoAndExecutionContext(targetAdapter, valueAdapterOrNull);
-    }
-
-    private void setupCommandTarget(
-            final ManagedObject targetAdapter,
-            final ManagedObject valueAdapter) {
-
-        final String arguments = CommandUtil.argDescriptionFor(valueAdapter);
-        setupCommandTarget(targetAdapter, arguments);
+        setupCommandTarget(targetAdapter);
+        setupCommandLogicalMemberIdentifier();
+        val dto = createCommandDto(targetAdapter, valueAdapterOrNull);
+        setupCommandDtoAndExecutionContext(dto);
     }
 
-    private void setupCommandMementoAndExecutionContext(
-            final ManagedObject targetAdapter,
-            final ManagedObject valueAdapterOrNull) {
-
-        final CommandDtoServiceInternal commandDtoServiceInternal = getCommandDtoService();
-        final CommandDto dto = commandDtoServiceInternal.asCommandDto(
+    private CommandDto createCommandDto(ManagedObject targetAdapter, ManagedObject valueAdapterOrNull) {
+        return getCommandDtoServiceInternal().asCommandDto(
                 Collections.singletonList(targetAdapter), this, valueAdapterOrNull);
-
-        setupCommandDtoAndExecutionContext(dto);
-
     }
 
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuetypes/ValueTypeDefinition.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuetypes/ValueTypeDefinition.java
index 18779e8..023bb7b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuetypes/ValueTypeDefinition.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuetypes/ValueTypeDefinition.java
@@ -36,10 +36,12 @@ public class ValueTypeDefinition {
     public static ValueTypeDefinition from(final Map.Entry<Class<?>, ValueType> entry) {
         return new ValueTypeDefinition(entry.getKey(), entry.getValue());
     }
+
+    Class<?> clazz;
+    ValueType valueType;
+
     private ValueTypeDefinition(Class<?> clazz, ValueType valueType) {
         this.clazz = clazz;
         this.valueType = valueType;
     }
-    private final Class<?> clazz;
-    private final ValueType valueType;
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuetypes/ValueTypeProviderForBuiltin.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuetypes/ValueTypeProviderForBuiltin.java
index 8d346c0..f9de0c6 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuetypes/ValueTypeProviderForBuiltin.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/valuetypes/ValueTypeProviderForBuiltin.java
@@ -28,6 +28,7 @@ import org.springframework.stereotype.Component;
 import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.graph.SimpleEdge;
 import org.apache.isis.applib.graph.tree.LazyTreeNode;
+import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.core.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.services.appfeat.ApplicationFeature;
 import org.apache.isis.schema.common.v2.ValueType;
@@ -41,12 +42,14 @@ public class ValueTypeProviderForBuiltin implements ValueTypeProvider {
     public Collection<ValueTypeDefinition> definitions() {
         return _Lists.of(
                     
+                    ValueTypeDefinition.of(Bookmark.class, ValueType.STRING),
+
                     // these are not yet part of the schema (do not map onto any value-types there)
                     ValueTypeDefinition.of(SimpleEdge.class, ValueType.STRING),
                     ValueTypeDefinition.of(LazyTreeNode.class, ValueType.STRING),
-                    
+
                     ValueTypeDefinition.of(ApplicationFeature.class, ValueType.STRING)
-                    
+
                 );
     }
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest.java
index 68053f0..a0e15b3 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest.java
@@ -28,7 +28,6 @@ import org.junit.After;
 import org.junit.Before;
 
 import org.apache.isis.applib.services.HasUniqueId;
-import org.apache.isis.core.config.metamodel.facets.CommandActionsConfiguration;
 import org.apache.isis.core.config.metamodel.facets.PublishActionsConfiguration;
 import org.apache.isis.core.metamodel.facets.AbstractFacetFactoryJUnit4TestCase;
 import org.apache.isis.core.metamodel.facets.object.domainobject.domainevents.ActionDomainEventDefaultFacetForDomainObjectAnnotation;
@@ -105,11 +104,6 @@ public class ActionAnnotationFacetFactoryTest extends AbstractFacetFactoryJUnit4
 
     }
 
-    void allowingCommandConfigurationToReturn(CommandActionsConfiguration value) {
-        val config = metaModelContext.getConfiguration();
-        config.getApplib().getAnnotation().getAction().setCommand(value);
-    }
-
     void allowingPublishingConfigurationToReturn(PublishActionsConfiguration value) {
         val config = metaModelContext.getConfiguration();
         config.getApplib().getAnnotation().getAction().setPublishing(value);
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_Command.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_Command.java
index f322a8a..950e122 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_Command.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_Command.java
@@ -29,11 +29,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.CommandPersistence;
-import org.apache.isis.applib.annotation.CommandReification;
 import org.apache.isis.applib.annotation.SemanticsOf;
-import org.apache.isis.core.config.metamodel.facets.CommandActionsConfiguration;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facets.FacetFactory.ProcessMethodContext;
 import org.apache.isis.core.metamodel.facets.actions.action.command.CommandFacetForActionAnnotation;
@@ -64,220 +60,19 @@ public class ActionAnnotationFacetFactoryTest_Command extends ActionAnnotationFa
         // then
         final Facet facet = facetedMethod.getFacet(CommandFacet.class);
         assertNull(facet);
-
-    }
-
-    @Test
-    public void given_noAnnotation_and_configurationSetToIgnoreQueryOnly_andSafeSemantics_thenNone() {
-
-        // given
-        allowingCommandConfigurationToReturn(CommandActionsConfiguration.IGNORE_QUERY_ONLY);
-        final Method actionMethod = findMethod(ActionAnnotationFacetFactoryTest.Customer.class, "someAction");
-
-        facetedMethod.addFacet(new ActionSemanticsFacetAbstract(SemanticsOf.SAFE, facetedMethod) {});
-
-        // when
-        processCommand(facetFactory, new ProcessMethodContext(ActionAnnotationFacetFactoryTest.Customer.class, null,
-                actionMethod, mockMethodRemover, facetedMethod));
-
-        // then
-        final Facet facet = facetedMethod.getFacet(CommandFacet.class);
-        assertNull(facet);
-    }
-
-    @Test
-    public void given_noAnnotation_and_configurationSetToIgnoreQueryOnly_andNonSafeSemantics_thenAdded() {
-
-        // given
-        allowingCommandConfigurationToReturn(CommandActionsConfiguration.IGNORE_QUERY_ONLY);
-        final Method actionMethod = findMethod(ActionAnnotationFacetFactoryTest.Customer.class, "someAction");
-
-        facetedMethod.addFacet(new ActionSemanticsFacetAbstract(SemanticsOf.IDEMPOTENT, facetedMethod) {});
-
-        // when
-        processCommand(facetFactory, new ProcessMethodContext(ActionAnnotationFacetFactoryTest.Customer.class, null,
-                actionMethod, mockMethodRemover, facetedMethod));
-
-        // then
-        final Facet facet = facetedMethod.getFacet(CommandFacet.class);
-        assertNotNull(facet);
-        assertTrue(facet instanceof  CommandFacetFromConfiguration);
-        final CommandFacetFromConfiguration facetImpl = (CommandFacetFromConfiguration) facet;
-        assertThat(facetImpl.persistence(), is(org.apache.isis.applib.annotation.CommandPersistence.PERSISTED));
-        assertThat(facetImpl.executeIn(), is(org.apache.isis.applib.annotation.CommandExecuteIn.FOREGROUND));
-    }
-
-    @Test(expected=IllegalStateException.class)
-    public void given_noAnnotation_and_configurationSetToIgnoreQueryOnly_andNoSemantics_thenException() {
-
-        // given
-        allowingCommandConfigurationToReturn(CommandActionsConfiguration.IGNORE_QUERY_ONLY);
-        final Method actionMethod = findMethod(ActionAnnotationFacetFactoryTest.Customer.class, "someAction");
-
-        // when
-        processCommand(facetFactory, new ProcessMethodContext(ActionAnnotationFacetFactoryTest.Customer.class, null,
-                actionMethod, mockMethodRemover, facetedMethod));
-    }
-
-    @Test
-    public void given_noAnnotation_and_configurationSetToNone_thenNone() {
-
-        // given
-        allowingCommandConfigurationToReturn(CommandActionsConfiguration.NONE);
-        final Method actionMethod = findMethod(ActionAnnotationFacetFactoryTest.Customer.class, "someAction");
-
-        // when
-        processCommand(facetFactory, new ProcessMethodContext(ActionAnnotationFacetFactoryTest.Customer.class, null,
-                actionMethod, mockMethodRemover, facetedMethod));
-
-        // then
-        final Facet facet = facetedMethod.getFacet(PublishedActionFacet.class);
-        assertNull(facet);
-    }
-
-    @Test
-    public void given_noAnnotation_and_configurationSetToAll_thenFacetAdded() {
-
-        // given
-        final Method actionMethod = findMethod(ActionAnnotationFacetFactoryTest.Customer.class, "someAction");
-
-        allowingCommandConfigurationToReturn(CommandActionsConfiguration.ALL);
-
-        // when
-        processCommand(facetFactory, new ProcessMethodContext(ActionAnnotationFacetFactoryTest.Customer.class, null,
-                actionMethod, mockMethodRemover, facetedMethod));
-
-        // then
-        final Facet facet = facetedMethod.getFacet(CommandFacet.class);
-        assertNotNull(facet);
-        assert(facet instanceof CommandFacetFromConfiguration);
-    }
-
-    @Test
... 10580 lines suppressed ...