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/09 07:31:50 UTC

[isis] branch ISIS-2222 updated (f0c5233 -> 7248a47)

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

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


    from f0c5233  ISIS-2222: now runs, though background commands broken
     new bfffbd4   ISIS-2222: reworking command, lots of stuff here...
     new 3e8b897   ISIS-2222: reworking command, further improvements and removal of background command stuff
     new 7248a47   ISIS-2222: reworking command, lots of stuff here...

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../applib-ant/examples/annotation/Action.java     |  32 -
 .../examples/annotation/CommandExecuteIn.java      |  83 ---
 .../examples/annotation/CommandPersistence.java    |  52 --
 .../applib-ant/examples/annotation/Nature.java     |  16 +
 .../applib-ant/examples/annotation/Property.java   |  34 +-
 .../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 -
 .../examples}/layout/menubars/HasNamed.java        |   0
 .../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 +-
 .../examples/services/DomainChangeRecord.java      | 155 +++++
 .../DomainChangeRecord_openTargetObject.java       |  61 ++
 .../applib-svc/examples/services/HasUsername.java  |   4 +
 .../background/BackgroundCommandService.java       |  59 --
 .../examples/services/background/package-info.java |  27 -
 .../examples/services/bookmark/Bookmark.java       |   1 +
 .../examples/services/command/Command.java         | 408 ++++-------
 .../examples/services/command/CommandContext.java  |  21 +-
 .../examples/services/command/CommandDefault.java  | 182 -----
 .../CommandDtoProcessorForActionAbstract.java      |   4 +-
 .../CommandDtoProcessorForPropertyAbstract.java    |   4 +-
 .../services/command/CommandExecutorService.java   |   4 +-
 .../examples/services/command}/CommandService.java |   2 +-
 .../services/command/spi/CommandService.java       |  65 --
 .../ContentMappingServiceForCommandDto.java        |  37 +-
 .../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 +-
 .../services/wrapper/control/ControlAbstract.java  |  17 +-
 .../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 ----
 .../_BackgroundCommandExecution.adoc               |  25 -
 .../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/DomainChangeAbstract.java | 296 --------
 .../isis/applib/services/DomainChangeRecord.java   | 155 +++++
 .../DomainChangeRecord_openTargetObject.java       |  61 ++
 .../applib/services/TransactionScopeListener.java  |   9 +-
 .../background/BackgroundCommandService.java       |  59 --
 .../applib/services/background/package-info.java   |  27 -
 .../isis/applib/services/bookmark/Bookmark.java    |   1 +
 .../isis/applib/services/command/Command.java      | 412 ++++-------
 .../applib/services/command/CommandContext.java    |  25 +-
 .../applib/services/command/CommandDefault.java    | 186 -----
 .../services/command/CommandDtoProcessor.java      |   1 -
 .../CommandDtoProcessorForActionAbstract.java      |   4 +-
 .../CommandDtoProcessorForPropertyAbstract.java    |   4 +-
 .../services/command/CommandExecutorService.java   |  15 +-
 .../applib/services/command/CommandService.java    |  92 +++
 .../CommandServiceListener.java}                   |  27 +-
 .../ContentMappingServiceForCommandDto.java        |  38 +-
 .../services/conmap/command/UserDataKeys.java}     |  21 +-
 .../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 +
 .../apache/isis/core/config/IsisConfiguration.java |  33 +-
 .../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 +------
 .../transaction/ChangedObjectsService.java         |   1 -
 .../IsisModuleCoreRuntimeServices.java             |   3 -
 .../background/BackgroundCommandExecution.java     |  74 --
 .../background/CommandExecutionAbstract.java       |  58 --
 .../command/CommandDtoServiceInternalDefault.java  |  22 +-
 .../command/CommandExecutorServiceDefault.java     | 127 ++--
 .../QueryResultsCacheDefault.java                  |  44 +-
 .../scratchpad/ScratchpadDefault.java              |   4 +-
 .../runtimeservices/sudo/SudoServiceDefault.java   |  14 +-
 .../xactn/TransactionServiceSpring.java            |  14 +
 .../WrapperFactoryDefault_wrappedObject_Test.java  |   4 -
 examples/demo/domain/pom.xml                       |  11 +-
 .../src/main/java/demoapp/dom/DemoModule.java      |   5 +-
 .../ActionCommandDisabledMetaAnnotation.java       |   5 +-
 .../Action/command/ActionCommandJdo.java           |  42 +-
 .../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_publishedObjects.java |  39 --
 .../Property/publishing/PropertyPublishingJdo.java |   4 +-
 ...tyPublishingJdo_clearInteractionExecutions.java |  34 -
 ...ropertyPublishingJdo_interactionExecutions.java |  40 --
 .../spiimpl/PublisherServiceSpiForProperties.java  |  48 --
 .../_changes/ExposeCapturedChanges.java            |   9 +
 .../_changes/ExposeCapturedChanges_changes.java    |  35 +
 .../ExposeCapturedChanges_clear.java}              |  12 +-
 .../PublisherServiceToCaptureChangesInMemory.java} |   4 +-
 .../_commands/ExposePersistedCommands.java         |  24 +
 .../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 +-
 .../demo/domain/src/main/resources/application.yml |   5 +
 .../java/demoapp/webapp/vaadin/DemoAppVaadin.java  |   2 +-
 ...ackgroundCommandsQuartzJobConfigurerModule.java |  15 +-
 .../wicket/src/main/resources/log4j2-spring.xml    |   7 +-
 .../testdomain/conf/Configuration_headless.java    |   7 +-
 extensions/core/command-log/impl/pom.xml           |  19 +-
 .../impl/src/main/java/META-INF/persistence.xml    |   1 +
 .../impl/CommandServiceListenerForJdo.java         |  51 +-
 .../impl/IsisModuleExtCommandLogImpl.java          |  29 +-
 ...ndExecutionFromBackgroundCommandServiceJdo.java |  29 -
 .../background/BackgroundCommandServiceJdo.java    |  92 ---
 .../BackgroundCommandServiceJdoRepository.java     |  48 --
 .../extensions/commandlog/impl/jdo/CommandJdo.java | 760 ++++++++-------------
 ...doRepository.java => CommandJdoRepository.java} | 230 ++++---
 .../impl/jdo/CommandJdo_childCommands.java         |  31 +-
 .../impl/jdo/CommandJdo_openResultObject.java      |  36 +-
 .../commandlog/impl/jdo/CommandJdo_retry.java      |  89 +--
 .../impl/jdo/CommandJdo_siblingCommands.java       |  39 +-
 .../commandlog/impl/jdo/CommandServiceJdo.java     |  99 ---
 .../commandlog/impl/jdo/ReplayState.java           |  34 +
 .../impl/mixins/HasUniqueId_command.java           |   7 +-
 .../mixins/HasUsername_recentCommandsByUser.java   |   6 +-
 .../impl/mixins/Object_recentCommands.java         |   4 +-
 .../{T_backgroundCommands.java => T_recent.java}   |  24 +-
 .../commandlog/impl/ui/CommandServiceMenu.java     |  11 +-
 .../commandlog/impl/util/BigDecimalUtils.java      |  32 +
 .../commandlog/impl/util/StringUtils.java          |  17 +
 .../impl/util/StringUtils_trimmed_Test.java        |  28 +
 .../impl/IsisModuleExtCommandReplayImpl.java       |   8 +-
 .../impl/analysis/CommandReplayAnalyser.java       |   8 +-
 .../analysis/CommandReplayAnalyserAbstract.java    |   9 +-
 .../CommandReplayAnalyserExceptionStr.java         |  21 +-
 ...mandReplayAnalyserNumberBackgroundCommands.java |  89 ---
 .../analysis/CommandReplayAnalyserResultStr.java   |  35 +-
 .../analysis/CommandReplayAnalysisService.java     |  32 +-
 .../impl/clock/TickingClockService.java            |  13 +-
 .../executor/CommandExecutorServiceWithTime.java   |  49 +-
 .../impl/executor/ReplayableCommandExecution.java  |  95 ++-
 .../commandreplay/impl/fetch/CommandFetcher.java   |   7 +-
 .../impl/mixins/CommandJdo_download.java           |  11 +-
 .../impl/mixins/CommandJdo_exclude.java            |   5 +-
 .../impl/mixins/CommandJdo_replayNext.java         |  33 +-
 .../impl/mixins/CommandJdo_replayQueue.java        |   6 +-
 ...kgroundCommandsWithReplicationAndReplayJob.java |  34 +-
 ...ice.java => CommandReplayOnPrimaryService.java} |  59 +-
 ...e.java => CommandReplayOnSecondaryService.java} |  31 +-
 .../CommandReplayAnalysisService_trimmed_Test.java |  30 -
 ...{RunBackgroundCommandsJob.java => DemoJob.java} |  10 +-
 .../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 +
 .../service/JdoPersistenceLifecycleService.java    |  13 +-
 .../IsisBookmarkConverter.java}                    |  16 +-
 .../IsisLocalResourcePathConverter.java            |   2 +-
 .../{ => applib}/IsisMarkupConverter.java          |   2 +-
 .../{ => applib}/IsisPasswordConverter.java        |   2 +-
 .../v2/IsisChangesDtoConverter.java}               |  16 +-
 .../v2/IsisCommandDtoConverter.java}               |  18 +-
 .../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/IsisIntegrationTestAbstract.java        |  26 +-
 .../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 |  27 +-
 .../scalars/bookmark/BookmarkPanelFactory.java     |  27 +-
 .../scalars/markup/MarkupPanelFactories.java       |   5 +-
 .../ui/components/scalars/oiddto/OidDtoPanel.java  |  27 +-
 .../scalars/oiddto/OidDtoPanelFactory.java         |  25 +-
 .../wicket/ui/panels/FormExecutorDefault.java      |  12 +-
 .../wicket/viewer/mixins/Object_clearHints.java    |  36 +-
 .../ComponentFactoryRegistrarDefault.java          |   7 +
 243 files changed, 3247 insertions(+), 6445 deletions(-)
 delete mode 100644 api/applib/src/main/adoc/modules/applib-ant/examples/annotation/CommandExecuteIn.java
 delete mode 100644 api/applib/src/main/adoc/modules/applib-ant/examples/annotation/CommandPersistence.java
 copy api/applib/src/main/{java/org/apache/isis/applib => adoc/modules/applib-classes/examples}/layout/menubars/HasNamed.java (100%)
 delete mode 100644 api/applib/src/main/adoc/modules/applib-classes/examples/util/JaxbAdapters.java
 create mode 100644 api/applib/src/main/adoc/modules/applib-svc/examples/services/DomainChangeRecord.java
 create mode 100644 api/applib/src/main/adoc/modules/applib-svc/examples/services/DomainChangeRecord_openTargetObject.java
 delete mode 100644 api/applib/src/main/adoc/modules/applib-svc/examples/services/background/BackgroundCommandService.java
 delete mode 100644 api/applib/src/main/adoc/modules/applib-svc/examples/services/background/package-info.java
 delete mode 100644 api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDefault.java
 rename api/applib/src/main/{java/org/apache/isis/applib/services/command/spi => adoc/modules/applib-svc/examples/services/command}/CommandService.java (97%)
 delete mode 100644 api/applib/src/main/adoc/modules/applib-svc/examples/services/command/spi/CommandService.java
 delete mode 100644 api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundCommandService.adoc
 delete mode 100644 api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundService.adoc
 delete mode 100644 api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundService/_BackgroundCommandExecution.adoc
 delete mode 100644 api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundService/_Quartz.adoc
 delete mode 100644 api/applib/src/main/java/org/apache/isis/applib/annotation/CommandExecuteIn.java
 delete mode 100644 api/applib/src/main/java/org/apache/isis/applib/annotation/CommandPersistence.java
 delete mode 100644 api/applib/src/main/java/org/apache/isis/applib/services/DomainChangeAbstract.java
 create mode 100644 api/applib/src/main/java/org/apache/isis/applib/services/DomainChangeRecord.java
 create mode 100644 api/applib/src/main/java/org/apache/isis/applib/services/DomainChangeRecord_openTargetObject.java
 delete mode 100644 api/applib/src/main/java/org/apache/isis/applib/services/background/BackgroundCommandService.java
 delete mode 100644 api/applib/src/main/java/org/apache/isis/applib/services/background/package-info.java
 delete mode 100644 api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDefault.java
 create mode 100644 api/applib/src/main/java/org/apache/isis/applib/services/command/CommandService.java
 rename api/applib/src/main/java/org/apache/isis/applib/services/command/{CommandWithDto.java => spi/CommandServiceListener.java} (63%)
 rename api/applib/src/main/{adoc/modules/applib-svc/examples/services/command/CommandWithDto.java => java/org/apache/isis/applib/services/conmap/command/UserDataKeys.java} (64%)
 create mode 100644 api/applib/src/main/java/org/apache/isis/applib/services/tablecol/TableColumnOrderForCollectionTypeAbstract.java
 delete mode 100644 core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/BackgroundCommandExecution.java
 delete mode 100644 core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/CommandExecutionAbstract.java
 delete mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_backgroundCommands.java
 delete mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_clearBackgroundCommands.java
 delete mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_clearForegroundCommands.java
 delete mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_executeBackgroundCommands.java
 delete mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_foregroundCommands.java
 delete mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/CommandServiceSpiForActions.java
 delete mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/spiimpl/ActionPublishingJdo_clearInteractionExecutions.java
 delete mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/spiimpl/ActionPublishingJdo_interactionExecutions.java
 delete mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingVm_publishedObjects.java
 delete mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/spiimpl/PropertyPublishingJdo_clearInteractionExecutions.java
 delete mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/spiimpl/PropertyPublishingJdo_interactionExecutions.java
 delete mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/spiimpl/PublisherServiceSpiForProperties.java
 create mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_changes/ExposeCapturedChanges.java
 create mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_changes/ExposeCapturedChanges_changes.java
 rename examples/demo/domain/src/main/java/demoapp/dom/annotDomain/{DomainObject/publishing/spiimpl/DomainObjectPublishingVm_clearPublishedObjects.java => _changes/ExposeCapturedChanges_clear.java} (59%)
 rename examples/demo/domain/src/main/java/demoapp/dom/annotDomain/{DomainObject/publishing/spiimpl/PublisherServiceSpiForDomainObject.java => _changes/PublisherServiceToCaptureChangesInMemory.java} (87%)
 create mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_commands/ExposePersistedCommands.java
 create mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_commands/ExposePersistedCommands_commands.java
 create mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/ExposeCapturedInteractions.java
 create mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/ExposeCapturedInteractions_clear.java
 create mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/ExposeCapturedInteractions_interactions.java
 create mode 100644 examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/InteractionDtoVm.java
 copy examples/demo/domain/src/main/java/demoapp/dom/annotDomain/{Action/publishing/ActionPublishingJdo.layout.xml => _interactions/InteractionDtoVm.layout.xml} (97%)
 rename examples/demo/domain/src/main/java/demoapp/dom/annotDomain/{Action/publishing/spiimpl/PublisherServiceSpiForActions.java => _interactions/PublisherServiceToCaptureInteractionsInMemory.java} (89%)
 rename core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandServiceDefault.java => extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/CommandServiceListenerForJdo.java (51%)
 delete mode 100644 extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/background/BackgroundCommandExecutionFromBackgroundCommandServiceJdo.java
 delete mode 100644 extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/background/BackgroundCommandServiceJdo.java
 delete mode 100644 extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/background/BackgroundCommandServiceJdoRepository.java
 rename extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/{CommandServiceJdoRepository.java => CommandJdoRepository.java} (57%)
 delete mode 100644 extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandServiceJdo.java
 rename extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/{T_backgroundCommands.java => T_recent.java} (58%)
 create mode 100644 extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/util/BigDecimalUtils.java
 create mode 100644 extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/util/StringUtils.java
 create mode 100644 extensions/core/command-log/impl/src/test/java/org/apache/isis/extensions/commandlog/impl/util/StringUtils_trimmed_Test.java
 delete mode 100644 extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserNumberBackgroundCommands.java
 rename extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/{CommandReplayOnMasterService.java => CommandReplayOnPrimaryService.java} (73%)
 rename extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/{CommandReplayOnSlaveService.java => CommandReplayOnSecondaryService.java} (67%)
 delete mode 100644 extensions/core/command-replay/impl/src/test/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService_trimmed_Test.java
 rename extensions/core/quartz/impl/src/main/java/org/apache/isis/extensions/quartz/jobs/{RunBackgroundCommandsJob.java => DemoJob.java} (68%)
 delete mode 100644 legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/background/BackgroundCommandService2.java
 delete mode 100644 legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/background/BackgroundService.java
 delete mode 100644 legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/background/BackgroundService2.java
 copy persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/{IsisMarkupConverter.java => applib/IsisBookmarkConverter.java} (70%)
 copy persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/{ => applib}/IsisLocalResourcePathConverter.java (98%)
 copy persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/{ => applib}/IsisMarkupConverter.java (98%)
 rename persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/{ => applib}/IsisPasswordConverter.java (98%)
 copy persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/{IsisLocalResourcePathConverter.java => schema/v2/IsisChangesDtoConverter.java} (72%)
 copy persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/{IsisLocalResourcePathConverter.java => schema/v2/IsisCommandDtoConverter.java} (67%)
 rename persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/{IsisLocalResourcePathConverter.java => schema/v2/IsisInteractionDtoConverter.java} (71%)
 copy persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/{IsisMarkupConverter.java => schema/v2/IsisOidDtoConverter.java} (64%)
 rename persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuemappings/{ => applib}/ByteArrayBlobRdbmsMapping.java (98%)
 rename persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuetypes/{ => applib}/IsisBlobMapping.java (99%)
 rename persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuetypes/{ => applib}/IsisClobMapping.java (99%)
 copy persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java => viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/bookmark/BookmarkPanel.java (59%)
 copy persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java => viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/bookmark/BookmarkPanelFactory.java (53%)
 copy persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java => viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/oiddto/OidDtoPanel.java (59%)
 rename persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java => viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/oiddto/OidDtoPanelFactory.java (59%)


[isis] 03/03: ISIS-2222: reworking command, lots of stuff here...

Posted by da...@apache.org.
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 7248a4779b90fa69b099481abebde6ec603a1626
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Wed Sep 9 08:31:25 2020 +0100

     ISIS-2222: reworking command, lots of stuff here...
---
 .../examples/services/DomainChangeRecord.java      | 155 +++++++++++++++++++++
 .../DomainChangeRecord_openTargetObject.java       |  61 ++++++++
 .../services/command/spi/CommandService.java       |  65 ---------
 .../applib/annotation/CommandReification.java}     |  34 +++--
 .../applib/services/command/CommandService.java    |  92 ++++++++++++
 .../command/spi/CommandServiceListener.java}       |  27 ++--
 .../impl/CommandServiceListenerForJdo.java         |  50 ++++---
 .../impl/util/StringUtils_trimmed_Test.java        |  28 ++++
 .../CommandReplayAnalysisService_trimmed_Test.java |  30 ----
 9 files changed, 403 insertions(+), 139 deletions(-)

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..ea81d3f
--- /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="Class")
+    @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/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-ant/examples/annotation/CommandPersistence.java b/api/applib/src/main/java/org/apache/isis/applib/annotation/CommandReification.java
similarity index 50%
rename from api/applib/src/main/adoc/modules/applib-ant/examples/annotation/CommandPersistence.java
rename to api/applib/src/main/java/org/apache/isis/applib/annotation/CommandReification.java
index 7f7000a..a2b8b68 100644
--- a/api/applib/src/main/adoc/modules/applib-ant/examples/annotation/CommandPersistence.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/annotation/CommandReification.java
@@ -19,34 +19,38 @@
 package org.apache.isis.applib.annotation;
 
 /**
- * Whether the command should be persisted.
+ * The available policies as to whether action invocations are reified into commands.
  */
 // tag::refguide[]
-public enum CommandPersistence {
-
+public enum CommandReification {
     // 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.
+     * Whether the action should be handled as a command as per the default command configured in <tt>applicationp.properties</tt>.
+     *
+     * <p>
+     *     If no command policy is configured, then the action is <i>not</i> treated as a command.
+     * </p>
      */
     // tag::refguide[]
-    PERSISTED,
+    AS_CONFIGURED,
     // 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.
+     * Handle the action as a command, irrespective of any configuration settings.
      */
     // tag::refguide[]
-    IF_HINTED,
+    ENABLED,
     // 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).
+     * Do not handle the action as a command, irrespective of any configuration settings.
      */
     // tag::refguide[]
-    NOT_PERSISTED
-
+    DISABLED,
+    // end::refguide[]
+    /**
+     * Ignore the value provided by this annotation (meaning that the framework will keep searching, in meta
+     * annotations or superclasses/interfaces).
+     */
+    // tag::refguide[]
+    NOT_SPECIFIED
 }
 // end::refguide[]
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/adoc/modules/applib-svc/examples/services/command/CommandWithDto.java b/api/applib/src/main/java/org/apache/isis/applib/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/java/org/apache/isis/applib/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/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.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/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandServiceDefault.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/CommandServiceListenerForJdo.java
similarity index 51%
rename from core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandServiceDefault.java
rename to extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/CommandServiceListenerForJdo.java
index 527692f..f3a4d81 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandServiceDefault.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/CommandServiceListenerForJdo.java
@@ -16,39 +16,53 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.core.runtimeservices.command;
+package org.apache.isis.extensions.commandlog.impl;
 
+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.OrderPrecedence;
 import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.spi.CommandService;
+import org.apache.isis.applib.services.command.spi.CommandServiceListener;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
+
+import lombok.RequiredArgsConstructor;
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
 
 @Service
-@Named("isisRuntimeServices.CommandServiceDefault")
-@Order(OrderPrecedence.LATE)
-@Primary
-@Qualifier("Default")
-public class CommandServiceDefault implements CommandService {
+@Named("isisExtensionsCommandLog.CommandCompletionHook")
+@Order(OrderPrecedence.MIDPOINT) // after JdoPersistenceLifecycleService
+@Qualifier("Jdo")
+@Log4j2
+@RequiredArgsConstructor
+public class CommandServiceListenerForJdo implements CommandServiceListener {
 
-    @Override
-    public Command create() {
-        return new CommandDefault();
-    }
+    @Inject final CommandJdoRepository commandJdoRepository;
 
     @Override
-    public void complete(final Command command) {
-        // nothing to do
-    }
+    public void onComplete(Command command) {
 
-    @Override
-    public boolean persistIfPossible(final Command command) {
-        return false;
+        if(!command.isSystemStateChanged()) {
+            return;
+        }
+
+        val commandJdo = new CommandJdo(command);
+        val parent = command.getParent();
+        val parentJdo =
+            parent != null
+                ? commandJdoRepository
+                    .findByUniqueId(parent.getUniqueId())
+                    .orElse(null)
+                : null;
+        commandJdo.setParent(parentJdo);
+
+        commandJdoRepository.persist(commandJdo);
     }
 
 }
diff --git a/extensions/core/command-log/impl/src/test/java/org/apache/isis/extensions/commandlog/impl/util/StringUtils_trimmed_Test.java b/extensions/core/command-log/impl/src/test/java/org/apache/isis/extensions/commandlog/impl/util/StringUtils_trimmed_Test.java
new file mode 100644
index 0000000..b991b25
--- /dev/null
+++ b/extensions/core/command-log/impl/src/test/java/org/apache/isis/extensions/commandlog/impl/util/StringUtils_trimmed_Test.java
@@ -0,0 +1,28 @@
+package org.apache.isis.extensions.commandlog.impl.util;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class StringUtils_trimmed_Test {
+
+    @Test
+    public void fits() {
+        Assertions.assertThat(StringUtils.trimmed("abcde", 5)).isEqualTo("abcde");
+    }
+
+    @Test
+    public void needs_to_be_trimmed() {
+        Assertions.assertThat(StringUtils.trimmed("abcde", 4)).isEqualTo("a...");
+    }
+
+    @Test
+    public void when_null() {
+        Assertions.assertThat(StringUtils.trimmed(null, 4)).isNull();
+    }
+
+    @Test
+    public void when_empty() {
+        Assertions.assertThat(StringUtils.trimmed("", 4)).isEqualTo("");
+    }
+
+}
\ No newline at end of file
diff --git a/extensions/core/command-replay/impl/src/test/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService_trimmed_Test.java b/extensions/core/command-replay/impl/src/test/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService_trimmed_Test.java
deleted file mode 100644
index babe14e..0000000
--- a/extensions/core/command-replay/impl/src/test/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService_trimmed_Test.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.apache.isis.extensions.commandreplay.impl.analysis;
-
-import org.assertj.core.api.Assertions;
-import org.junit.jupiter.api.Test;
-
-import org.apache.isis.extensions.commandreplay.impl.analysis.CommandReplayAnalysisService;
-
-public class CommandReplayAnalysisService_trimmed_Test {
-
-    @Test
-    public void fits() {
-        Assertions.assertThat(CommandReplayAnalysisService.trimmed("abcde", 5)).isEqualTo("abcde");
-    }
-
-    @Test
-    public void needs_to_be_trimmed() {
-        Assertions.assertThat(CommandReplayAnalysisService.trimmed("abcde", 4)).isEqualTo("a...");
-    }
-
-    @Test
-    public void when_null() {
-        Assertions.assertThat(CommandReplayAnalysisService.trimmed(null, 4)).isNull();
-    }
-
-    @Test
-    public void when_empty() {
-        Assertions.assertThat(CommandReplayAnalysisService.trimmed("", 4)).isEqualTo("");
-    }
-
-}
\ No newline at end of file


[isis] 02/03: ISIS-2222: reworking command, further improvements and removal of background command stuff

Posted by da...@apache.org.
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 3e8b897415a989933a2f57fcc4d2749a54c5a9eb
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Wed Sep 9 08:31:02 2020 +0100

     ISIS-2222: reworking command, further improvements and removal of background command stuff
---
 .../applib-ant/examples/annotation/Action.java     |  31 --
 .../examples/annotation/CommandExecuteIn.java      |  83 -----
 .../applib-ant/examples/annotation/Nature.java     |  16 +
 .../applib-ant/examples/annotation/Property.java   |  33 +-
 .../modules/applib-ant/pages/Action/command.adoc   |  19 -
 .../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 -
 .../examples/layout/menubars/HasNamed.java}        |  17 +-
 .../examples/layout/menubars/Menu.java             |   7 +-
 .../examples/layout/menubars/MenuSection.java      |   2 +-
 .../layout/menubars/bootstrap3/BS3MenuSection.java |  12 +
 .../mixins/layout/Object_rebuildMetamodel.java     |  21 +-
 .../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 +-
 .../applib-svc/examples/services/HasUsername.java  |   4 +
 .../background/BackgroundCommandService.java       |  59 ---
 .../examples/services/bookmark/Bookmark.java       |   1 +
 .../examples/services/command/Command.java         | 405 ++++++++-------------
 .../examples/services/command/CommandContext.java  |  21 +-
 .../examples/services/command/CommandDefault.java  | 180 ---------
 .../CommandDtoProcessorForActionAbstract.java      |   4 +-
 .../CommandDtoProcessorForPropertyAbstract.java    |   4 +-
 .../services/command/CommandExecutorService.java   |   4 +-
 .../examples/services/command}/CommandService.java |   0
 .../ContentMappingServiceForCommandDto.java        |  36 +-
 .../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 +-
 .../services/wrapper/control/ControlAbstract.java  |  17 +-
 .../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 ------
 .../_BackgroundCommandExecution.adoc               |  25 --
 .../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  |  10 +-
 .../apache/isis/applib/annotation/Property.java    |  18 +-
 .../applib/services/TransactionScopeListener.java  |   9 +-
 .../applib/services/command/CommandContext.java    |  24 +-
 .../services/command/CommandDtoProcessor.java      |   1 -
 .../services/command/CommandExecutorService.java   |  11 +-
 .../ContentMappingServiceForCommandDto.java        |   8 +-
 .../services/conmap/command}/UserDataKeys.java     |   2 +-
 .../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 -
 .../commons/internal/exceptions/_Exceptions.java   |  14 +
 .../apache/isis/core/config/IsisConfiguration.java |  32 +-
 .../command/CommandFacetForActionAnnotation.java   |  13 +-
 ...ommandFacetForActionAnnotationAsConfigured.java |   6 +-
 .../command/CommandFacetFromConfiguration.java     |   7 +-
 ...ctionInvocationFacetForDomainEventAbstract.java | 109 +++---
 .../facets/actions/command/CommandFacet.java       |   2 -
 .../property/PropertyAnnotationFacetFactory.java   |   2 +-
 .../command/CommandFacetForPropertyAnnotation.java |  54 ++-
 ...mandFacetForPropertyAnnotationAsConfigured.java |   5 +-
 ...tySetterOrClearFacetForDomainEventAbstract.java | 130 +++----
 .../facets/schema/IsisSchemaValueTypeProvider.java |   2 +-
 .../metamodel/valuetypes/ValueTypeDefinition.java  |   6 +-
 .../action/ActionAnnotationFacetFactoryTest.java   |   6 -
 .../ActionAnnotationFacetFactoryTest_Command.java  | 227 +-----------
 .../transaction/ChangedObjectsService.java         |   1 -
 .../IsisModuleCoreRuntimeServices.java             |   3 -
 .../background/BackgroundCommandExecution.java     |  73 ----
 .../background/CommandExecutionAbstract.java       |  57 ---
 .../command/CommandExecutorServiceDefault.java     |  95 +++--
 .../QueryResultsCacheDefault.java                  |  44 +--
 .../scratchpad/ScratchpadDefault.java              |   4 +-
 .../runtimeservices/sudo/SudoServiceDefault.java   |  14 +-
 .../xactn/TransactionServiceSpring.java            |  14 +
 .../WrapperFactoryDefault_wrappedObject_Test.java  |   4 -
 examples/demo/domain/pom.xml                       |   3 -
 .../ActionCommandDisabledMetaAnnotation.java       |   2 +-
 .../Action/command/ActionCommandJdo.java           |  36 +-
 .../Action/command/ActionCommandJdo.layout.xml     |  29 +-
 .../command/spiimpl/ActionCommandJdo_commands.java |  39 --
 .../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_publishedObjects.java |  39 --
 .../Property/publishing/PropertyPublishingJdo.java |   4 +-
 ...tyPublishingJdo_clearInteractionExecutions.java |  34 --
 ...ropertyPublishingJdo_interactionExecutions.java |  40 --
 .../spiimpl/PublisherServiceSpiForProperties.java  |  48 ---
 .../_changes/ExposeCapturedChanges.java            |   9 +
 .../_changes/ExposeCapturedChanges_changes.java    |  35 ++
 .../ExposeCapturedChanges_clear.java}              |  12 +-
 .../PublisherServiceToCaptureChangesInMemory.java} |   4 +-
 .../_commands/ExposePersistedCommands.java         |  24 ++
 .../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 +-
 .../demo/domain/src/main/resources/application.yml |   5 +
 .../java/demoapp/webapp/vaadin/DemoAppVaadin.java  |   2 +-
 ...ackgroundCommandsQuartzJobConfigurerModule.java |  15 +-
 .../wicket/src/main/resources/log4j2-spring.xml    |   7 +-
 .../testdomain/conf/Configuration_headless.java    |   7 +-
 extensions/core/command-log/impl/pom.xml           |  19 +-
 .../impl/src/main/java/META-INF/persistence.xml    |   1 +
 .../impl/IsisModuleExtCommandLogImpl.java          |  21 +-
 .../extensions/commandlog/impl/jdo/CommandJdo.java | 246 +++++++------
 .../commandlog/impl/jdo/CommandJdoRepository.java  | 129 ++++---
 .../impl/jdo/CommandJdo_childCommands.java         |   8 +-
 .../impl/jdo/CommandJdo_openResultObject.java      |  18 +-
 .../commandlog/impl/jdo/CommandJdo_retry.java      |   2 +
 .../impl/jdo/CommandJdo_siblingCommands.java       |   8 +-
 .../mixins/HasUsername_recentCommandsByUser.java   |   5 +-
 .../{T_backgroundCommands.java => T_recent.java}   |  19 +-
 .../commandlog/impl/ui/CommandServiceMenu.java     |   4 +-
 .../commandlog/impl/util/BigDecimalUtils.java      |  32 ++
 .../commandlog/impl/util/StringUtils.java          |  17 +
 .../impl/IsisModuleExtCommandReplayImpl.java       |   8 +-
 .../impl/analysis/CommandReplayAnalyser.java       |   8 +-
 .../analysis/CommandReplayAnalyserAbstract.java    |   9 +-
 .../CommandReplayAnalyserExceptionStr.java         |  20 +-
 ...mandReplayAnalyserNumberBackgroundCommands.java |  90 -----
 .../analysis/CommandReplayAnalyserResultStr.java   |  34 +-
 .../analysis/CommandReplayAnalysisService.java     |  33 +-
 .../impl/clock/TickingClockService.java            |  13 +-
 .../executor/CommandExecutorServiceWithTime.java   |  46 ++-
 .../impl/executor/ReplayableCommandExecution.java  |  84 ++---
 .../commandreplay/impl/fetch/CommandFetcher.java   |   7 +-
 .../impl/mixins/CommandJdo_download.java           |  10 +-
 .../impl/mixins/CommandJdo_exclude.java            |   4 +-
 .../impl/mixins/CommandJdo_replayNext.java         |  22 +-
 .../impl/mixins/CommandJdo_replayQueue.java        |   2 +-
 ...kgroundCommandsWithReplicationAndReplayJob.java |  33 +-
 ...ice.java => CommandReplayOnPrimaryService.java} |  58 ++-
 ...e.java => CommandReplayOnSecondaryService.java} |  24 +-
 ...{RunBackgroundCommandsJob.java => DemoJob.java} |   6 +-
 .../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 +
 .../service/JdoPersistenceLifecycleService.java    |  13 +-
 .../applib/IsisBookmarkConverter.java              |   2 +-
 .../persistence/IsisPersistenceSessionJdoBase.java |   2 +-
 .../persistence/PersistenceSession5.java           |  74 +---
 .../applib/IsisIntegrationTestAbstract.java        |  26 +-
 .../resources/DomainObjectResourceServerside.java  |  24 +-
 .../resources/DomainServiceResourceServerside.java |  21 +-
 .../viewer/resources/ResourceAbstract.java         |   9 -
 .../wicket/ui/app/logout/LogoutHandlerWkt.java     |   6 +-
 .../CollectionContentsAsAjaxTablePanel.java        |   1 -
 .../scalars/markup/MarkupPanelFactories.java       |   5 +-
 .../wicket/viewer/mixins/Object_clearHints.java    |  36 +-
 179 files changed, 1852 insertions(+), 3722 deletions(-)

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 26d5ca3..8d4a22f 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
@@ -90,37 +90,6 @@ public @interface Action {
 
     // end::refguide[]
     /**
-     * Whether the action invocation should be reified into a {@link org.apache.isis.applib.services.command.Command} object.
-     */
-    // tag::refguide[]
-    CommandReification command()                                    // <.>
-            default CommandReification.NOT_SPECIFIED;
-
-    // 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/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 cc2d0a9..1488a33 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
@@ -51,37 +51,6 @@ public @interface Property {
 
     // end::refguide[]
     /**
-     * Whether the property edit should be reified into a {@link org.apache.isis.applib.services.command.Command} object.
-     */
-    // tag::refguide[]
-    CommandReification command()                                // <.>
-            default CommandReification.NOT_SPECIFIED;
-
-    // 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>
@@ -209,7 +178,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 075c67a..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
@@ -278,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-svc/examples/services/background/package-info.java b/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/HasNamed.java
similarity index 69%
rename from api/applib/src/main/adoc/modules/applib-svc/examples/services/background/package-info.java
rename to api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/HasNamed.java
index f63812d..6627d86 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/background/package-info.java
+++ b/api/applib/src/main/adoc/modules/applib-classes/examples/layout/menubars/HasNamed.java
@@ -16,12 +16,13 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
+package org.apache.isis.applib.layout.menubars;
 
-/**
- * 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
- *
- *
- */
-package org.apache.isis.applib.services.background;
\ No newline at end of file
+import org.apache.isis.applib.annotation.Programmatic;
+
+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 82b7cc4..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
@@ -32,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 {
 
@@ -41,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-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/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 afa0be6..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,197 +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.events.domain.ActionDomainEvent;
 import org.apache.isis.applib.services.HasUniqueId;
+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[]
 
     /**
@@ -226,7 +160,8 @@ public interface Command extends HasUniqueId {
      * {@link Interaction.Execution#getStartedAt()}.
      */
     // tag::refguide[]
-    Timestamp getStartedAt();                   // <.>
+    @Getter
+    private Timestamp startedAt;                // <.>
     // end::refguide[]
 
     /**
@@ -243,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..8e50213 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,8 +20,7 @@ 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.annotation.Qualifier;
@@ -31,10 +30,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.inject.ServiceInjector;
 
 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}.
@@ -50,9 +49,12 @@ import lombok.extern.log4j.Log4j2;
 @Primary
 @Qualifier("Default")
 @IsisInteractionScope
-@Log4j2
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
+//@Log4j2
 public class CommandContext {
 
+    private final ServiceInjector serviceInjector;
+    
     @Getter
     private Command command;
 
@@ -62,13 +64,10 @@ public class CommandContext {
      */
     public void setCommand(final Command command) {
         this.command = command;
+        if(command!=null) {
+            serviceInjector.injectServicesInto(command);
+        }
     }
-
-    public Optional<Executor> getCurrentExecutor() {
-        return Optional.ofNullable(getCommand())
-                .map(Command::getExecutor);
-    }
-
     // tag::refguide[]
 }
 // end::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 e24b08b..0000000
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandDefault.java
+++ /dev/null
@@ -1,180 +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.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/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..c97685f 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,13 @@ public interface CommandExecutorService {
      * Executes the specified command.
      *
      * @param sudoPolicy
-     * @param commandWithDto
+     * @param command
      * @return - any exception raised by the command.
      */
     // tag::refguide[]
     void executeCommand(
             SudoPolicy sudoPolicy,          // <.>
-            CommandWithDto commandWithDto   // <.>
+            Command command                 // <.>
     );
 
     Bookmark executeCommand(
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandService.java
similarity index 100%
rename from api/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
rename to api/applib/src/main/adoc/modules/applib-svc/examples/services/command/CommandService.java
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 ef6925f..b96e6d3 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
@@ -31,6 +31,7 @@ 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;
@@ -61,27 +62,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;
@@ -94,7 +95,7 @@ public class ContentMappingServiceForCommandDto implements ContentMappingService
         if (commandDtoProcessor == null) {
             return commandDto;
         }
-        return commandDtoProcessor.process(commandWithDto, commandDto);
+        return commandDtoProcessor.process(command, commandDto);
     }
 
 
@@ -113,22 +114,15 @@ 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);
@@ -138,8 +132,8 @@ public class ContentMappingServiceForCommandDto implements ContentMappingService
                     CommandWithDto.USERDATA_KEY_EXCEPTION, command.getException());
 
             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/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/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/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 5e83704..2cd39a2 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/_BackgroundCommandExecution.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundService/_BackgroundCommandExecution.adoc
deleted file mode 100644
index 868417c..0000000
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/_BackgroundService/_BackgroundCommandExecution.adoc
+++ /dev/null
@@ -1,25 +0,0 @@
-= `BackgroundCommandExec'n` abstract class
-
-: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 reintroduced in v2.0
-
-The `BackgroundCommandExecution` (in isis-core) is an abstract template class provided by isis-core 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.
-
-
-
-
-
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 8d4a22f..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,7 +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.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;
@@ -90,6 +90,14 @@ public @interface Action {
 
     // end::refguide[]
     /**
+     * Whether the action invocation should be reified into a {@link org.apache.isis.applib.services.command.Command} object.
+     */
+    // tag::refguide[]
+    CommandReification command()                                    // <.>
+            default CommandReification.NOT_SPECIFIED;
+
+    // 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/Property.java b/api/applib/src/main/java/org/apache/isis/applib/annotation/Property.java
index 1488a33..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,7 +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.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;
@@ -51,16 +50,19 @@ public @interface Property {
 
     // end::refguide[]
     /**
+     * Whether the property edit should be reified into a
+     * {@link org.apache.isis.applib.services.command.Command} object.
+     */
+    // tag::refguide[]
+    CommandReification command()                                // <.>
+            default CommandReification.NOT_SPECIFIED;
+
+    // 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>
      */
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/command/CommandContext.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandContext.java
index 8e50213..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,7 +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.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;
@@ -45,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;
 
@@ -68,6 +73,19 @@ public class CommandContext {
             serviceInjector.injectServicesInto(command);
         }
     }
+
+    @Override
+    public void destroy() throws Exception {
+        setCommand(null);
+    }
+
+    @Override
+    public void onTransactionEnded() {
+        getCommand().internal().setSystemStateChanged(
+                getCommand().isSystemStateChanged() ||
+                metricsService.numberObjectsDirtied() > 0);
+    }
+
     // tag::refguide[]
 }
 // end::refguide[]
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/CommandExecutorService.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandExecutorService.java
index c97685f..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
@@ -52,8 +52,17 @@ public interface CommandExecutorService {
      * @return - any exception raised by the command.
      */
     // tag::refguide[]
-    void executeCommand(
+    Bookmark executeCommand(
+            SudoPolicy sudoPolicy,          // <.>
+            Command command                 // <.>
+    );
+
+    Bookmark executeCommand(
             SudoPolicy sudoPolicy,          // <.>
+            CommandDto commandDto           // <.>
+    );
+
+    Bookmark executeCommand(
             Command command                 // <.>
     );
 
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 b96e6d3..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;
@@ -39,6 +40,7 @@ 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;
 
@@ -125,11 +127,13 @@ public class ContentMappingServiceForCommandDto implements ContentMappingService
 
             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/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/api/UserDataKeys.java b/api/applib/src/main/java/org/apache/isis/applib/services/conmap/command/UserDataKeys.java
similarity index 95%
rename from extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/api/UserDataKeys.java
rename to api/applib/src/main/java/org/apache/isis/applib/services/conmap/command/UserDataKeys.java
index d603b90..5559f40 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/api/UserDataKeys.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/conmap/command/UserDataKeys.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.extensions.commandlog.impl.api;
+package org.apache.isis.applib.services.conmap.command;
 
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
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/core/commons/src/main/java/org/apache/isis/core/commons/internal/exceptions/_Exceptions.java b/core/commons/src/main/java/org/apache/isis/core/commons/internal/exceptions/_Exceptions.java
index 741d271..8899e5c 100644
--- a/core/commons/src/main/java/org/apache/isis/core/commons/internal/exceptions/_Exceptions.java
+++ b/core/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/java/org/apache/isis/core/config/IsisConfiguration.java b/core/config/src/main/java/org/apache/isis/core/config/IsisConfiguration.java
index 2b2ffa4..22c4f48 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,6 +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.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;
@@ -648,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#getCommandDto()}) 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
@@ -835,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#getCommandDto()}) 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;
@@ -1486,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;
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 8798f14..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,6 +21,7 @@ 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.CommandReification;
 import org.apache.isis.applib.services.command.CommandDtoProcessor;
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.core.config.IsisConfiguration;
@@ -45,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) {
@@ -68,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");
@@ -107,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, 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 dca1c21..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
@@ -24,13 +24,9 @@ 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 0232d2c..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
@@ -29,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, 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/command/CommandFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacet.java
index 314e6d9..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
@@ -33,7 +33,5 @@ import org.apache.isis.core.metamodel.facetapi.Facet;
  */
 public interface CommandFacet extends Facet {
 
-    public CommandPersistence persistence();
-
     public CommandDtoProcessor getProcessor();
 }
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 558ba6a..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,6 +20,7 @@ package org.apache.isis.core.metamodel.facets.properties.property.command;
 
 import java.util.Optional;
 
+import org.apache.isis.applib.annotation.CommandReification;
 import org.apache.isis.applib.annotation.Property;
 import org.apache.isis.applib.services.command.CommandDtoProcessor;
 import org.apache.isis.applib.services.inject.ServiceInjector;
@@ -29,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 {
 
@@ -43,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) {
@@ -83,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, 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 330775e..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
@@ -24,11 +24,8 @@ 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/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/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 deb5634..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
@@ -30,7 +30,6 @@ import static org.junit.Assert.assertTrue;
 
 import org.apache.isis.applib.annotation.Action;
 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;
@@ -61,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
-    public void given_asConfigured_and_configurationSetToIgnoreQueryOnly_andSafeSemantics_thenNone() {
-
-        class Customer {
-            @Action(command = CommandReification.AS_CONFIGURED)
-            public void someAction() {
-            }
-        }
-
-        allowingCommandConfigurationToReturn(CommandActionsConfiguration.IGNORE_QUERY_ONLY);
-        final Method actionMethod = findMethod(Customer.class, "someAction");
-
-        facetedMethod.addFacet(new ActionSemanticsFacetAbstract(SemanticsOf.SAFE, facetedMethod) {});
-
-        processCommand(facetFactory, new ProcessMethodContext(Customer.class, null, actionMethod, mockMethodRemover, facetedMethod));
-
-        final Facet facet = facetedMethod.getFacet(CommandFacet.class);
-        assertNull(facet);
-    }
-
-    @Test
-    public void given_asConfigured_and_configurationSetToIgnoreQueryOnly_andNonSafeSemantics_thenAdded() {
-
-        // given
-        class Customer {
-            @Action(
-                    command = CommandReification.AS_CONFIGURED,
-                    commandPersistence = CommandPersistence.IF_HINTED,
-                    commandExecuteIn = CommandExecuteIn.BACKGROUND
-                    )
-            public void someAction() {
-            }
-        }
-
-        allowingCommandConfigurationToReturn(CommandActionsConfiguration.IGNORE_QUERY_ONLY);
-        final Method actionMethod = findMethod(Customer.class, "someAction");
-
-        facetedMethod.addFacet(new ActionSemanticsFacetAbstract(SemanticsOf.IDEMPOTENT, facetedMethod) {});
-
-        // when
-        processCommand(facetFactory, new ProcessMethodContext(Customer.class, null, actionMethod, mockMethodRemover, facetedMethod));
-
-        // then
-        final Facet facet = facetedMethod.getFacet(CommandFacet.class);
-        assertNotNull(facet);
-        final CommandFacetForActionAnnotationAsConfigured facetImpl = (CommandFacetForActionAnnotationAsConfigured) facet;
-        assertThat(facetImpl.persistence(), is(org.apache.isis.applib.annotation.CommandPersistence.IF_HINTED));
-        assertThat(facetImpl.executeIn(), is(org.apache.isis.applib.annotation.CommandExecuteIn.BACKGROUND));
-    }
-
-    @Test(expected=IllegalStateException.class)
-    public void given_asConfigured_and_configurationSetToIgnoreQueryOnly_andNoSemantics_thenException() {
-
-        class Customer {
-            @Action(command = CommandReification.AS_CONFIGURED)
-            public void someAction() {
-            }
-        }
-
-        allowingCommandConfigurationToReturn(CommandActionsConfiguration.IGNORE_QUERY_ONLY);
-        final Method actionMethod = findMethod(Customer.class, "someAction");
-
-        processCommand(facetFactory, new ProcessMethodContext(Customer.class, null, actionMethod, mockMethodRemover, facetedMethod));
     }
 
     @Test
-    public void given_asConfigured_and_configurationSetToNone_thenNone() {
-
-        class Customer {
-            @Action(command = CommandReification.AS_CONFIGURED)
-            public void someAction() {
-            }
-        }
-
-        allowingCommandConfigurationToReturn(CommandActionsConfiguration.NONE);
-        final Method actionMethod = findMethod(Customer.class, "someAction");
-
-        processCommand(facetFactory, new ProcessMethodContext(Customer.class, null, actionMethod, mockMethodRemover, facetedMethod));
-
-        final Facet facet = facetedMethod.getFacet(CommandFacet.class);
-        assertNull(facet);
-    }
-
-    @Test
-    public void given_asConfigured_and_configurationSetToAll_thenFacetAdded() {
+    public void given_annotation_then_facet_added() {
 
         // given
         class Customer {
-            @Action(
-                    command = CommandReification.AS_CONFIGURED,
-                    commandPersistence = CommandPersistence.IF_HINTED,
-                    commandExecuteIn = CommandExecuteIn.BACKGROUND
-                    )
+            @Action()
             public void someAction() {
             }
         }
         final Method actionMethod = findMethod(Customer.class, "someAction");
 
-        allowingCommandConfigurationToReturn(CommandActionsConfiguration.ALL);
-
-        // when
-        processCommand(facetFactory, new ProcessMethodContext(Customer.class, null, actionMethod, mockMethodRemover, facetedMethod));
-
-        // then
-        final Facet facet = facetedMethod.getFacet(CommandFacet.class);
-        assertNotNull(facet);
-        final CommandFacetForActionAnnotationAsConfigured facetImpl = (CommandFacetForActionAnnotationAsConfigured) facet;
-        assertThat(facetImpl.persistence(), is(org.apache.isis.applib.annotation.CommandPersistence.IF_HINTED));
-        assertThat(facetImpl.executeIn(), is(org.apache.isis.applib.annotation.CommandExecuteIn.BACKGROUND));
-    }
-
-    @Test
-    public void given_enabled_irrespectiveOfConfiguration_thenFacetAdded() {
-
-        // given
-        class Customer {
-            @Action(command = CommandReification.ENABLED)
-            public void someAction() {
-            }
-        }
-        final Method actionMethod = findMethod(Customer.class, "someAction");
-
-        // even though configuration is disabled
-        allowingCommandConfigurationToReturn(CommandActionsConfiguration.NONE);
-
         // when
         processCommand(facetFactory, new ProcessMethodContext(Customer.class, null, actionMethod, mockMethodRemover, facetedMethod));
 
@@ -284,27 +82,6 @@ public class ActionAnnotationFacetFactoryTest_Command extends ActionAnnotationFa
         assertTrue(facet instanceof CommandFacetForActionAnnotation);
     }
 
-    @Test
-    public void given_disabled_irrespectiveOfConfiguration_thenNone() {
-
-        // given
-        class Customer {
-            @Action(command = CommandReification.DISABLED)
-            public void someAction() {
-            }
-        }
-        final Method actionMethod = findMethod(Customer.class, "someAction");
-
-        // even though configuration is disabled
-        allowingCommandConfigurationToReturn(CommandActionsConfiguration.NONE);
-
-        // when
-        processCommand(facetFactory, new ProcessMethodContext(Customer.class, null, actionMethod, mockMethodRemover, facetedMethod));
-
-        // then
-        final Facet facet = facetedMethod.getFacet(CommandFacet.class);
-        assertNull(facet);
-    }
 
 
 }
\ No newline at end of file
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/transaction/ChangedObjectsService.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/transaction/ChangedObjectsService.java
index fb25302..1b5398d 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/transaction/ChangedObjectsService.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/transaction/ChangedObjectsService.java
@@ -51,7 +51,6 @@ import lombok.val;
 @Order(OrderPrecedence.EARLY)
 @Primary
 @Qualifier("Default")
-@IsisInteractionScope
 //@Log4j2
 public class ChangedObjectsService implements TransactionScopeListener {
 
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/IsisModuleCoreRuntimeServices.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/IsisModuleCoreRuntimeServices.java
index 0d55a64..34db8ee 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/IsisModuleCoreRuntimeServices.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/IsisModuleCoreRuntimeServices.java
@@ -26,13 +26,11 @@ import org.springframework.context.annotation.Import;
 import org.springframework.core.OrderComparator;
 import org.springframework.core.annotation.AnnotationAwareOrderComparator;
 
-import org.apache.isis.applib.services.wrapper.control.AsyncControlService;
 import org.apache.isis.core.codegen.bytebuddy.IsisModuleCoreCodegenByteBuddy;
 import org.apache.isis.core.runtime.IsisModuleCoreRuntime;
 import org.apache.isis.core.runtimeservices.bookmarks.BookmarkServiceDefault;
 import org.apache.isis.core.runtimeservices.command.CommandDtoServiceInternalDefault;
 import org.apache.isis.core.runtimeservices.command.CommandExecutorServiceDefault;
-import org.apache.isis.core.runtimeservices.command.CommandServiceDefault;
 import org.apache.isis.core.runtimeservices.confmenu.ConfigurationViewServiceDefault;
 import org.apache.isis.core.runtimeservices.email.EmailServiceDefault;
 import org.apache.isis.core.runtimeservices.eventbus.EventBusServiceSpring;
@@ -71,7 +69,6 @@ import org.apache.isis.core.runtimeservices.xmlsnapshot.XmlSnapshotServiceDefaul
         BookmarkServiceDefault.class,
         CommandDtoServiceInternalDefault.class,
         CommandExecutorServiceDefault.class,
-        CommandServiceDefault.class,
         ConfigurationViewServiceDefault.class,
         EmailNotificationServiceDefault.class,
         EmailServiceDefault.class,
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/BackgroundCommandExecution.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/BackgroundCommandExecution.java
deleted file mode 100644
index 16a9667..0000000
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/BackgroundCommandExecution.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.core.runtimeservices.background;
-
-import java.util.List;
-
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.CommandExecutorService;
-import org.apache.isis.core.commons.internal.collections._Lists;
-
-import lombok.val;
-import lombok.extern.log4j.Log4j2;
-
-/**
- * Intended to be used as a base class for executing queued up {@link Command background action}s.
- *
- * <p>
- * This implementation uses the {@link #findBackgroundCommandsToExecute() hook method} so that it is
- * independent of the location where the actions have actually been persisted to.
- */
-@Log4j2
-public abstract class BackgroundCommandExecution extends CommandExecutionAbstract {
-
-    /**
-     * Defaults to the historical defaults * for running background commands.
-     */
-    public BackgroundCommandExecution() {
-        this(CommandExecutorService.SudoPolicy.NO_SWITCH);
-    }
-
-    public BackgroundCommandExecution(final CommandExecutorService.SudoPolicy sudoPolicy) {
-        super(sudoPolicy);
-    }
-
-    // //////////////////////////////////////
-
-    @Override
-    protected void doExecute(Object context) {
-
-        val commands = _Lists.<Command>newArrayList();
-        transactionService.executeWithinTransaction(() -> {
-            commands.addAll(findBackgroundCommandsToExecute());
-        });
-
-        log.debug("Found {} to execute", commands.size());
-
-        for (val command : commands) {
-            execute((CommandWithDto) command, transactionService);
-        }
-    }
-
-    /**
-     * Mandatory hook method
-     */
-    protected abstract List<? extends Command> findBackgroundCommandsToExecute();
-
-}
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/CommandExecutionAbstract.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/CommandExecutionAbstract.java
deleted file mode 100644
index 113fd7f..0000000
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/CommandExecutionAbstract.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.core.runtimeservices.background;
-
-import javax.inject.Inject;
-
-import org.apache.isis.applib.services.command.CommandExecutorService;
-import org.apache.isis.applib.services.xactn.TransactionService;
-import org.apache.isis.core.runtime.iactn.template.AbstractIsisInteractionTemplate;
-
-/**
- */
-public abstract class CommandExecutionAbstract extends AbstractIsisInteractionTemplate {
-
-    @Inject protected CommandExecutorService commandExecutorService;
-    
-    private final CommandExecutorService.SudoPolicy sudoPolicy;
-
-    protected CommandExecutionAbstract(final CommandExecutorService.SudoPolicy sudoPolicy) {
-        this.sudoPolicy = sudoPolicy;
-    }
-
-    /**
-     * Executes the command within a transaction, and with respect to the {@link CommandExecutorService.SudoPolicy}
-     * specified in the constructor.
-     *
-     * <p>
-     *     Uses {@link CommandExecutorService} to actually execute the command.
-     * </p>
-     */
-    protected final void execute(final CommandWithDto commandWithDto, TransactionService transactionService) {
-        transactionService.executeWithinTransaction(()->{
-
-            // the executor service will handle any exceptions thrown.
-            commandExecutorService.executeCommand(sudoPolicy, commandWithDto);
-
-        });
-    }
-
-
-}
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
index ca87863..16195b9 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
@@ -22,6 +22,8 @@ import java.sql.Timestamp;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.concurrent.Callable;
+import java.util.function.Supplier;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -77,6 +79,7 @@ import org.apache.isis.schema.common.v2.OidsDto;
 import org.apache.isis.schema.common.v2.ValueWithTypeDto;
 
 import lombok.Getter;
+import lombok.SneakyThrows;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
@@ -91,51 +94,44 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
     private static final Pattern ID_PARSER =
             Pattern.compile("(?<className>[^#]+)#?(?<localId>[^(]+)(?<args>[(][^)]*[)])?");
 
-    @Inject private BookmarkService bookmarkService;
-    @Inject private SudoService sudoService;
-    @Inject private ClockService clockService;
-    @Inject private TransactionService transactionService;
-    @Inject private IsisInteractionTracker isisInteractionTracker;
-    @Inject private javax.inject.Provider<InteractionContext> interactionContextProvider;
-    
-    @Inject @Getter private IsisInteractionFactory isisInteractionFactory;
-    @Inject @Getter private SpecificationLoader specificationLoader;
+    @Inject BookmarkService bookmarkService;
+    @Inject SudoService sudoService;
+    @Inject ClockService clockService;
+    @Inject TransactionService transactionService;
+    @Inject IsisInteractionTracker isisInteractionTracker;
+    @Inject javax.inject.Provider<InteractionContext> interactionContextProvider;
     
+    @Inject @Getter IsisInteractionFactory isisInteractionFactory;
+    @Inject @Getter SpecificationLoader specificationLoader;
+
+    @Override
+    public Bookmark executeCommand(final Command command) {
+        return executeCommand(SudoPolicy.NO_SWITCH, command);
+    }
+
     @Override
-    public void executeCommand(
+    public Bookmark executeCommand(
             final CommandExecutorService.SudoPolicy sudoPolicy,
             final Command command) {
 
-        final Runnable commandRunnable = ()->executeCommand(command);
-        final Runnable topLevelRunnable;
-
-        switch (sudoPolicy) {
-        case NO_SWITCH:
-            topLevelRunnable = commandRunnable;
-            break;
-        case SWITCH:
-            val user = command.getUsername();
-            topLevelRunnable = ()->sudoService.sudo(user, commandRunnable);
-            break;
-        default:
-            throw new IllegalStateException("Probable framework error, unrecognized sudoPolicy: " + sudoPolicy);
-        }
-
         try {
-
-            transactionService.executeWithinTransaction(topLevelRunnable);
+            val bookmark = transactionService.executeWithinTransaction(
+                    () ->
+                            sudoPolicy == SudoPolicy.SWITCH
+                                ? sudoService.sudo(command.getUsername(), () -> doExecuteCommand(command))
+                                : doExecuteCommand(command));
 
             afterCommit(command, /*exception*/null);
+            return bookmark;
 
-        } catch (Exception e) {
-
-            log.warn("Exception when executing : {}", command.getLogicalMemberIdentifier(), e);
-            afterCommit(command, e);
+        } catch (Exception ex) {
+            log.warn("Exception when executing : {}", command.getLogicalMemberIdentifier(), ex);
+            afterCommit(command, ex);
+            return null;
         }
-
     }
 
-    protected void executeCommand(final Command command) {
+    private Bookmark doExecuteCommand(final Command command) {
 
         // setup for us by IsisTransactionManager; will have the transactionId of the backgroundCommand
         val interaction = interactionContextProvider.get().getInteraction();
@@ -157,12 +153,37 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
 
         val dto = command.getCommandDto();
 
-        val resultBookmark = executeCommand(dto);
+        val resultBookmark = doExecuteCommand(dto);
         command.internal().setResult(resultBookmark);
+
+        return resultBookmark;
     }
 
     @Override
-    public Bookmark executeCommand(CommandDto dto) {
+    public Bookmark executeCommand(final CommandDto commandDto) {
+        return executeCommand(SudoPolicy.NO_SWITCH, commandDto);
+    }
+
+    @Override
+    public Bookmark executeCommand(
+            final SudoPolicy sudoPolicy
+            , final CommandDto commandDto) {
+
+        try {
+            return transactionService.executeWithinTransaction(
+                    () -> sudoPolicy == SudoPolicy.SWITCH
+                        ? sudoService.sudo(
+                            commandDto.getUser(),
+                            () -> doExecuteCommand(commandDto))
+                        : doExecuteCommand(commandDto));
+
+        } catch (Exception ex) {
+            log.warn("Exception when executing : {}", commandDto.getMember().getLogicalMemberIdentifier(), ex);
+            return null;
+        }
+    }
+
+    private Bookmark doExecuteCommand(CommandDto dto) {
 
         final MemberDto memberDto = dto.getMember();
         final String memberId = memberDto.getMemberIdentifier();
@@ -227,7 +248,9 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
         return null;
     }
 
-    protected void afterCommit(final Command command, final Exception exceptionIfAny) {
+    protected void afterCommit(
+            final Command command
+            , final Exception exceptionIfAny) {
 
         val interaction = interactionContextProvider.get().getInteraction();
 
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/queryresultscache/QueryResultsCacheDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/queryresultscache/QueryResultsCacheDefault.java
index dd759f8..3a5d60f 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/queryresultscache/QueryResultsCacheDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/queryresultscache/QueryResultsCacheDefault.java
@@ -47,14 +47,13 @@ import org.apache.isis.core.commons.internal.collections._Maps;
 import lombok.extern.log4j.Log4j2;
 
 /**
- * This service (API and implementation) provides a mechanism by which idempotent query results can be cached for the duration of an interaction.
- * Most commonly this allows otherwise &quot;naive&quot; - eg that makes a repository call many times within a loop - to
- * be performance tuned.  The benefit is that the algorithm of the business logic can remain easy to understand.
+ * This service (API and implementation) provides a mechanism by which
+ * idempotent query results can be cached for the duration of an interaction.
  *
- * <p>
- * This implementation has no UI and there is only one implementation (this class) in applib, it is annotated with
- * {@link org.apache.isis.applib.annotation.DomainService}.  This means that it is automatically registered and
- * available for use; no further configuration is required.
+ * Most commonly this allows otherwise &quot;naive&quot; - eg that makes a
+ * repository call many times within a loop - to be performance tuned.  The
+ * benefit is that the algorithm of the business logic can remain easy to
+ * understand.
  */
 @Service
 @Named("isisRuntime.QueryResultsCacheDefault")
@@ -192,6 +191,11 @@ public class QueryResultsCacheDefault implements QueryResultsCache, TransactionS
         cache.clear();
     }
 
+    @Override
+    public void destroy() throws Exception {
+        cache.clear();
+    }
+
     // -- HELPER
 
     @Autowired(required = false)
@@ -201,31 +205,5 @@ public class QueryResultsCacheDefault implements QueryResultsCache, TransactionS
         return _NullSafe.stream(cacheControl)
                 .anyMatch(c->c.isIgnoreCache());
     }
-    
-    // -- REMOVED
-    
-  //XXX not used    
-//  private <T> Value<T> get(final Class<?> callingClass, final String methodName, final Object... keys) {
-//      return get(new Key(callingClass, methodName, keys));
-//  }
-//
-//  @SuppressWarnings("unchecked")
-//  private <T> Value<T> get(final Key cacheKey) {
-//      Value<T> value = (Value<T>) cache.get(cacheKey);
-//      logHitOrMiss(cacheKey, value);
-//      return value;
-//  }
-    
-  //XXX not used    
-//  private <T> T execute(final Callable<T> callable, final Key cacheKey) {
-//      if(isIgnoreCache()) {
-//          try {
-//              return callable.call();
-//          } catch (Exception e) {
-//              throw new RuntimeException(e);
-//          }
-//      }
-//      return executeWithCaching(callable, cacheKey);
-//  }
 
 }
\ No newline at end of file
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/scratchpad/ScratchpadDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/scratchpad/ScratchpadDefault.java
index 8a9e369..4272062 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/scratchpad/ScratchpadDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/scratchpad/ScratchpadDefault.java
@@ -76,8 +76,8 @@ public class ScratchpadDefault implements Scratchpad {
     /**
      * Clear any user data.
      */
-    public void clear() {
+    @Override
+    public void destroy() throws Exception {
         userData.clear();
     }
-
 }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/sudo/SudoServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/sudo/SudoServiceDefault.java
index 727695c..930d16c 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/sudo/SudoServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/sudo/SudoServiceDefault.java
@@ -20,7 +20,7 @@
 package org.apache.isis.core.runtimeservices.sudo;
 
 import java.util.List;
-import java.util.concurrent.Callable;
+import java.util.function.Supplier;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -53,12 +53,10 @@ public class SudoServiceDefault implements SudoService {
     }
 
     @Override
-    public <T> T sudo(final String username, final Callable<T> callable) {
+    public <T> T sudo(final String username, final Supplier<T> supplier) {
         try {
             runAs(username, null);
-            return callable.call();
-        } catch (Exception e) {
-            throw new RuntimeException(e);
+            return supplier.get();
         } finally {
             releaseRunAs();
         }
@@ -75,12 +73,10 @@ public class SudoServiceDefault implements SudoService {
     }
 
     @Override
-    public <T> T sudo(final String username, final List<String> roles, final Callable<T> callable) {
+    public <T> T sudo(final String username, final List<String> roles, final Supplier<T> supplier) {
         try {
             runAs(username, roles);
-            return callable.call();
-        } catch (Exception e) {
-            throw new RuntimeException(e);
+            return supplier.get();
         } finally {
             releaseRunAs();
         }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/TransactionServiceSpring.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/TransactionServiceSpring.java
index 4d389d1..35a09aa 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/TransactionServiceSpring.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/TransactionServiceSpring.java
@@ -19,6 +19,7 @@
 
 package org.apache.isis.core.runtimeservices.xactn;
 
+import java.util.concurrent.Callable;
 import java.util.function.Supplier;
 
 import javax.annotation.Nonnull;
@@ -43,6 +44,7 @@ import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.runtime.persistence.transaction.IsisTransactionAspectSupport;
 import org.apache.isis.core.runtime.persistence.transaction.IsisTransactionObject;
 
+import lombok.SneakyThrows;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
@@ -131,6 +133,18 @@ public class TransactionServiceSpring implements TransactionService {
         });
     }
 
+    private <T> T executeWithinNewTransaction(Callable<T> callable) {
+
+        return transactionTemplate.execute(new TransactionCallback<T>() {
+            // the code in this method executes in a transactional context
+            @SneakyThrows
+            @Override
+            public T doInTransaction(TransactionStatus status) {
+                return callable.call();
+            }
+        });
+    }
+
     private <T> T executeWithinNewTransaction(Supplier<T> task) {
 
         return transactionTemplate.execute(new TransactionCallback<T>() {
diff --git a/core/runtimeservices/src/test/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault_wrappedObject_Test.java b/core/runtimeservices/src/test/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault_wrappedObject_Test.java
index 0a41974..bd76ba9 100644
--- a/core/runtimeservices/src/test/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault_wrappedObject_Test.java
+++ b/core/runtimeservices/src/test/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault_wrappedObject_Test.java
@@ -40,7 +40,6 @@ import org.junit.rules.ExpectedException;
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.Command.Executor;
 import org.apache.isis.applib.services.command.CommandContext;
 import org.apache.isis.applib.services.command.CommandExecutorService;
 import org.apache.isis.applib.services.factory.FactoryService;
@@ -194,9 +193,6 @@ public class WrapperFactoryDefault_wrappedObject_Test {
                 allowing(mockCommandContext).getCommand();
                 will(returnValue(mockCommand));
                 
-                allowing(mockCommandContext).getCurrentExecutor();
-                will(returnValue(Optional.of(Executor.USER)));
-
                 allowing(mockSpecificationLoader).loadSpecification(String.class);
                 will(returnValue(mockStringSpec));
 
diff --git a/examples/demo/domain/pom.xml b/examples/demo/domain/pom.xml
index 4e19164..f28e151 100644
--- a/examples/demo/domain/pom.xml
+++ b/examples/demo/domain/pom.xml
@@ -22,11 +22,8 @@
 	</parent>
 	
 	<artifactId>demo-domain</artifactId>
-
 	<name>Demo - Domain</name>
 
-	<packaging>jar</packaging>
-
 	<properties>
 	</properties>
 
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandDisabledMetaAnnotation.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandDisabledMetaAnnotation.java
index 21b53f8..fd271ba 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandDisabledMetaAnnotation.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandDisabledMetaAnnotation.java
@@ -9,7 +9,7 @@ import java.lang.annotation.Target;
 import org.apache.isis.applib.annotation.Action;
 
 //tag::class[]
-@Action(command = CommandReification.DISABLED)  // <.>
+@Action()                                       // <.>
 @Inherited
 @Target({
         ElementType.TYPE, ElementType.METHOD    // <.>
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.java
index cb9e6bd..503cd5c 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.java
@@ -39,6 +39,7 @@ import lombok.Getter;
 import lombok.Setter;
 
 import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
+import demoapp.dom.annotDomain._commands.ExposePersistedCommands;
 
 //tag::class[]
 @PersistenceCapable(identityType = IdentityType.DATASTORE, schema = "demo")
@@ -48,7 +49,8 @@ import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
         , objectType = "demo.ActionCommandJdo"
         , editing = Editing.DISABLED
 )
-public class ActionCommandJdo implements HasAsciiDocDescription {
+public class ActionCommandJdo
+        implements HasAsciiDocDescription, ExposePersistedCommands {
     // ...
 //end::class[]
 
@@ -56,7 +58,7 @@ public class ActionCommandJdo implements HasAsciiDocDescription {
         this.property = initialValue;
         this.propertyMetaAnnotated = initialValue;
         this.propertyMetaAnnotatedOverridden = initialValue;
-        this.propertyUpdateInBackground = initialValue;
+        this.propertyUpdateAsync = initialValue;
     }
 
     public String title() {
@@ -80,15 +82,14 @@ public class ActionCommandJdo implements HasAsciiDocDescription {
     private String propertyMetaAnnotatedOverridden;
 
     @Property()
-    @MemberOrder(name = "background", sequence = "1")
+    @MemberOrder(name = "async", sequence = "1")
     @Getter @Setter
-    private String propertyUpdateInBackground;
+    private String propertyUpdateAsync;
 //end::property[]
 
 //tag::annotation[]
     @Action(
-        command = CommandReification.ENABLED         // <.>
-        , semantics = SemanticsOf.IDEMPOTENT
+        semantics = SemanticsOf.IDEMPOTENT
         , associateWith = "property"
         , associateWithSequence = "1"
     )
@@ -128,8 +129,7 @@ public class ActionCommandJdo implements HasAsciiDocDescription {
 //tag::meta-annotation-overridden[]
     @ActionCommandDisabledMetaAnnotation        // <.>
     @Action(
-        command = CommandReification.ENABLED    // <.>
-        , semantics = SemanticsOf.IDEMPOTENT
+        semantics = SemanticsOf.IDEMPOTENT
         , associateWith = "propertyMetaAnnotatedOverridden"
         , associateWithSequence = "1"
     )
@@ -147,31 +147,27 @@ public class ActionCommandJdo implements HasAsciiDocDescription {
     }
 //end::meta-annotation-overridden[]
 
-//tag::background[]
+//tag::async[]
     @Action(
-        command = CommandReification.ENABLED                // <.>
-        , commandExecuteIn = CommandExecuteIn.BACKGROUND    // <.>
-        , semantics = SemanticsOf.IDEMPOTENT
-        , associateWith = "propertyUpdateInBackground"
+        semantics = SemanticsOf.IDEMPOTENT
+        , associateWith = "propertyUpdateAsync"
         , associateWithSequence = "1"
     )
     @ActionLayout(
-        describedAs =
-            "@Action(command = ENABLED, commandExecuteIn = BACKGROUND)"
+        describedAs = "@Action()"
     )
-    public ActionCommandJdo updatePropertyInBackground(final String value) {
+    public ActionCommandJdo updatePropertyAsync(final String value) {
         AsyncControl<Void> control = AsyncControl.control();
         ActionCommandJdo actionCommandJdo = this.wrapperFactory.asyncWrap(this, control);
         actionCommandJdo.updatePropertyUsingAnnotation(value);
-        // setPropertyUpdateInBackground(value);
         return this;
     }
-    public String default0UpdatePropertyInBackground() {
-        return getPropertyUpdateInBackground();
+    public String default0UpdatePropertyAsync() {
+        return getPropertyUpdateAsync();
     }
 
     @Inject WrapperFactory wrapperFactory;
-//end::background[]
+//end::async[]
 
 
 //tag::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.layout.xml
index 0e2cf8c..757b050 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.layout.xml
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.layout.xml
@@ -18,17 +18,21 @@
 	<bs3:row>
 		<bs3:col span="6">
 			<bs3:row>
-				<bs3:col span="12">
-					<cpt:fieldSet name="Annotated" id="annotation"/>
-					<cpt:fieldSet name="Contributed" id="contributed"/>
-					<cpt:fieldSet name="Meta-annotated" id="meta-annotated"/>
-					<cpt:fieldSet name="Meta-annotated Overridden" id="meta-annotated-overridden"/>
-					<cpt:fieldSet name="Background" id="background"/>
+				<bs3:col span="6">
+					<bs3:row>
+						<bs3:col span="12">
+							<cpt:fieldSet name="Annotated" id="annotation"/>
+							<cpt:fieldSet name="Async" id="async"/>
+						</bs3:col>
+					</bs3:row>
 				</bs3:col>
-			</bs3:row>
-			<bs3:row>
-				<bs3:col span="12">
-					<cpt:collection id="commands"/>
+				<bs3:col span="6">
+					<bs3:row>
+						<bs3:col span="12">
+							<cpt:fieldSet name="Meta-annotated" id="meta-annotated"/>
+							<cpt:fieldSet name="Meta-annotated Overridden" id="meta-annotated-overridden"/>
+						</bs3:col>
+					</bs3:row>
 				</bs3:col>
 			</bs3:row>
 			<bs3:row>
@@ -51,6 +55,11 @@
 		</bs3:col>
 	</bs3:row>
 	<bs3:row>
+		<bs3:col span="12">
+			<cpt:collection id="commands"/>
+		</bs3:col>
+	</bs3:row>
+	<bs3:row>
 		<bs3:col span="12" unreferencedCollections="true"/>
 	</bs3:row>
 
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_commands.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_commands.java
deleted file mode 100644
index c3fb8c2..0000000
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_commands.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package demoapp.dom.annotDomain.Action.command.spiimpl;
-
-import java.util.LinkedList;
-
-import javax.inject.Inject;
-
-import org.apache.isis.applib.annotation.Collection;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
-import org.apache.isis.schema.cmd.v2.CommandDto;
-
-import lombok.val;
-
-import demoapp.dom.annotDomain.Action.command.ActionCommandJdo;
-
-//tag::class[]
-@Collection
-public class ActionCommandJdo_commands {
-    // ...
-//end::class[]
-
-    private final ActionCommandJdo actionCommandJdo;
-    public ActionCommandJdo_commands(ActionCommandJdo actionCommandJdo) {
-        this.actionCommandJdo = actionCommandJdo;
-    }
-
-    //tag::class[]
-    public LinkedList<CommandDto> coll() {
-        val list = new LinkedList<CommandDto>();
-        commandJdoRepository.findCompleted()
-                .stream().map(CommandJdo::getCommandDto)
-                .forEach(list::push);   // reverse order
-        return list;
-    }
-
-    @Inject
-    CommandJdoRepository commandJdoRepository;
-}
-//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo.java
index 526dbae..42f1fb3 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo.java
@@ -37,6 +37,7 @@ import lombok.Getter;
 import lombok.Setter;
 
 import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
+import demoapp.dom.annotDomain._interactions.ExposeCapturedInteractions;
 
 //tag::class[]
 @PersistenceCapable(identityType = IdentityType.DATASTORE, schema = "demo")
@@ -46,7 +47,8 @@ import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
         , objectType = "demo.ActionPublishingJdo"
         , editing = Editing.DISABLED
 )
-public class ActionPublishingJdo implements HasAsciiDocDescription {
+public class ActionPublishingJdo
+        implements HasAsciiDocDescription, ExposeCapturedInteractions {
     // ...
 //end::class[]
 
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo.layout.xml
index a9500e1..c18182f 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo.layout.xml
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo.layout.xml
@@ -27,7 +27,7 @@
 			</bs3:row>
 			<bs3:row>
 				<bs3:col span="12">
-					<cpt:collection id="interactionExecutions"/>
+					<cpt:collection id="interactions"/>
 				</bs3:col>
 			</bs3:row>
 			<bs3:row>
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/spiimpl/ActionPublishingJdo_clearInteractionExecutions.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/spiimpl/ActionPublishingJdo_clearInteractionExecutions.java
deleted file mode 100644
index cde9d30..0000000
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/spiimpl/ActionPublishingJdo_clearInteractionExecutions.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package demoapp.dom.annotDomain.Action.publishing.spiimpl;
-
-import javax.inject.Inject;
-
-import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.SemanticsOf;
-
-import demoapp.dom.annotDomain.Action.publishing.ActionPublishingJdo;
-
-//tag::class[]
-@Action(
-    semantics = SemanticsOf.IDEMPOTENT
-    , associateWith = "interactionExecutions"
-)
-public class ActionPublishingJdo_clearInteractionExecutions {
-    // ...
-//end::class[]
-
-    private final ActionPublishingJdo actionPublishingJdo;
-
-    public ActionPublishingJdo_clearInteractionExecutions(ActionPublishingJdo actionPublishingJdo) {
-        this.actionPublishingJdo = actionPublishingJdo;
-    }
-
-//tag::class[]
-    public ActionPublishingJdo act() {
-        publisherServiceSpiForActions.clear();
-        return actionPublishingJdo;
-    }
-
-    @Inject
-    PublisherServiceSpiForActions publisherServiceSpiForActions;
-}
-//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/spiimpl/ActionPublishingJdo_interactionExecutions.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/spiimpl/ActionPublishingJdo_interactionExecutions.java
deleted file mode 100644
index e068dd9..0000000
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/spiimpl/ActionPublishingJdo_interactionExecutions.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package demoapp.dom.annotDomain.Action.publishing.spiimpl;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-import org.apache.isis.applib.annotation.Collection;
-import org.apache.isis.schema.ixn.v2.InteractionDto;
-
-import lombok.val;
-
-import demoapp.dom.annotDomain.Action.publishing.ActionPublishingJdo;
-
-//tag::class[]
-@Collection
-public class ActionPublishingJdo_interactionExecutions {
-    // ...
-//end::class[]
-
-    private final ActionPublishingJdo actionPublishingJdo;
-
-    public ActionPublishingJdo_interactionExecutions(ActionPublishingJdo actionPublishingJdo) {
-        this.actionPublishingJdo = actionPublishingJdo;
-    }
-
-//tag::class[]
-    public List<InteractionDto> coll() {
-        val list = new LinkedList<InteractionDto>();
-        publisherServiceSpiForActions
-                .streamInteractionDtos()
-                .forEach(list::push);   // reverse order
-        return list;
-    }
-
-    @Inject
-    private PublisherServiceSpiForActions publisherServiceSpiForActions;
-}
-//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.java
index 7c3650c..90002d3 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.java
@@ -18,29 +18,16 @@
  */
 package demoapp.dom.annotDomain.DomainObject.publishing;
 
-import javax.jdo.annotations.DatastoreIdentity;
-import javax.jdo.annotations.IdGeneratorStrategy;
-import javax.jdo.annotations.IdentityType;
-import javax.jdo.annotations.PersistenceCapable;
-
-import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.Bounding;
-import org.apache.isis.applib.annotation.DomainObject;
-import org.apache.isis.applib.annotation.DomainObjectLayout;
 import org.apache.isis.applib.annotation.Editing;
 import org.apache.isis.applib.annotation.MemberOrder;
-import org.apache.isis.applib.annotation.Nature;
 import org.apache.isis.applib.annotation.Property;
-import org.apache.isis.applib.annotation.Publishing;
-import org.apache.isis.applib.annotation.SemanticsOf;
-
-import lombok.Getter;
-import lombok.Setter;
 
 import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
+import demoapp.dom.annotDomain._changes.ExposeCapturedChanges;
 
 //tag::class[]
-public interface DomainObjectPublishingJdo extends HasAsciiDocDescription {
+public interface DomainObjectPublishingJdo
+        extends HasAsciiDocDescription, ExposeCapturedChanges {
 
     @Property(editing = Editing.ENABLED)
     @MemberOrder(name = "property", sequence = "1")
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm-description.adoc
index b28a636..b6131e6 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm-description.adoc
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm-description.adoc
@@ -1,4 +1,4 @@
-The `publishing` semantic for a domain object means that all registered implementation(s) of the link:https://isis.apache.org/refguide/2.0.0-M3/applib-svc/PublisherService.html#spi[`PublisherService` SPI] will be notified of the identity and nature of the change (created/updated/deleted) to the domain object.
+The `_publishing` semantic for a domain object means that all registered implementation(s) of the link:https://isis.apache.org/refguide/2.0.0-M3/applib-svc/PublisherService.html#spi[`PublisherService` SPI] will be notified of the identity and nature of the change (created/updated/deleted) to the domain object.
 This is done _after_ the interaction in which the object(s) was changed has completed.
 
 This notification is done only once per interaction, so will include _all_ domain objects that were changed.
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingVm_publishedObjects.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingVm_publishedObjects.java
deleted file mode 100644
index d03ea3e..0000000
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingVm_publishedObjects.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package demoapp.dom.annotDomain.DomainObject.publishing.spiimpl;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-import org.apache.isis.applib.annotation.Collection;
-import org.apache.isis.schema.chg.v2.ChangesDto;
-
-import lombok.val;
-
-import demoapp.dom.annotDomain.DomainObject.publishing.DomainObjectPublishingVm;
-
-//tag::class[]
-@Collection
-public class DomainObjectPublishingVm_publishedObjects {
-    // ...
-//end::class[]
-
-    private final DomainObjectPublishingVm domainObjectPublishingVm;
-
-    public DomainObjectPublishingVm_publishedObjects(DomainObjectPublishingVm domainObjectPublishingVm) {
-        this.domainObjectPublishingVm = domainObjectPublishingVm;
-    }
-
-//tag::class[]
-    public List<ChangesDto> coll() {
-        val list = new LinkedList<ChangesDto>();
-        publisherServiceSpiForDomainObject
-                .streamPublishedObjects()
-                .forEach(list::push);   // reverse order
-        return list;
-    }
-
-    @Inject
-    PublisherServiceSpiForDomainObject publisherServiceSpiForDomainObject;
-}
-//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/PropertyPublishingJdo.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/PropertyPublishingJdo.java
index 5f0ebee..ebd7b54 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/PropertyPublishingJdo.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/PropertyPublishingJdo.java
@@ -36,6 +36,7 @@ import lombok.Getter;
 import lombok.Setter;
 
 import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
+import demoapp.dom.annotDomain._interactions.ExposeCapturedInteractions;
 
 //tag::class[]
 @PersistenceCapable(identityType = IdentityType.DATASTORE, schema = "demo")
@@ -45,7 +46,8 @@ import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
         , objectType = "demo.PropertyPublishingJdo"
         , editing = Editing.ENABLED
 )
-public class PropertyPublishingJdo implements HasAsciiDocDescription {
+public class PropertyPublishingJdo
+        implements HasAsciiDocDescription, ExposeCapturedInteractions {
     // ...
 //end::class[]
 
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/spiimpl/PropertyPublishingJdo_clearInteractionExecutions.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/spiimpl/PropertyPublishingJdo_clearInteractionExecutions.java
deleted file mode 100644
index 3454bbf..0000000
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/spiimpl/PropertyPublishingJdo_clearInteractionExecutions.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package demoapp.dom.annotDomain.Property.publishing.spiimpl;
-
-import javax.inject.Inject;
-
-import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.SemanticsOf;
-
-import demoapp.dom.annotDomain.Property.publishing.PropertyPublishingJdo;
-
-//tag::class[]
-@Action(
-    semantics = SemanticsOf.IDEMPOTENT
-    , associateWith = "interactionExecutions"
-)
-public class PropertyPublishingJdo_clearInteractionExecutions {
-    // ...
-//end::class[]
-
-    private final PropertyPublishingJdo propertyPublishingJdo;
-
-    public PropertyPublishingJdo_clearInteractionExecutions(PropertyPublishingJdo propertyPublishingJdo) {
-        this.propertyPublishingJdo = propertyPublishingJdo;
-    }
-
-//tag::class[]
-    public PropertyPublishingJdo act() {
-        publisherServiceSpiForProperties.clear();
-        return propertyPublishingJdo;
-    }
-
-    @Inject
-    PublisherServiceSpiForProperties publisherServiceSpiForProperties;
-}
-//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/spiimpl/PropertyPublishingJdo_interactionExecutions.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/spiimpl/PropertyPublishingJdo_interactionExecutions.java
deleted file mode 100644
index b1adbca..0000000
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/spiimpl/PropertyPublishingJdo_interactionExecutions.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package demoapp.dom.annotDomain.Property.publishing.spiimpl;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import javax.inject.Inject;
-
-import org.apache.isis.applib.annotation.Collection;
-import org.apache.isis.schema.ixn.v2.InteractionDto;
-
-import lombok.val;
-
-import demoapp.dom.annotDomain.Property.publishing.PropertyPublishingJdo;
-
-//tag::class[]
-@Collection
-public class PropertyPublishingJdo_interactionExecutions {
-    // ...
-//end::class[]
-
-    private final PropertyPublishingJdo propertyPublishingJdo;
-
-    public PropertyPublishingJdo_interactionExecutions(PropertyPublishingJdo propertyPublishingJdo) {
-        this.propertyPublishingJdo = propertyPublishingJdo;
-    }
-
-//tag::class[]
-    public List<InteractionDto> coll() {
-        val list = new LinkedList<InteractionDto>();
-        publisherServiceSpiForProperties
-                .streamInteractionDtos()
-                .forEach(list::push);   // reverse order
-        return list;
-    }
-
-    @Inject
-    PublisherServiceSpiForProperties publisherServiceSpiForProperties;
-}
-//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/spiimpl/PublisherServiceSpiForProperties.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/spiimpl/PublisherServiceSpiForProperties.java
deleted file mode 100644
index b196435..0000000
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/spiimpl/PublisherServiceSpiForProperties.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package demoapp.dom.annotDomain.Property.publishing.spiimpl;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Stream;
-
-import org.springframework.stereotype.Service;
-
-import org.apache.isis.applib.services.iactn.Interaction;
-import org.apache.isis.applib.services.publish.PublishedObjects;
-import org.apache.isis.applib.services.publish.PublisherService;
-import org.apache.isis.applib.util.schema.InteractionDtoUtils;
-import org.apache.isis.schema.ixn.v2.InteractionDto;
-
-import lombok.val;
-
-//tag::class[]
-@Service
-public class PublisherServiceSpiForProperties implements PublisherService {
-
-    private final List<InteractionDto> executions = new ArrayList<>();
-
-    @Override
-    public void publish(Interaction.Execution<?, ?> execution) {
-        val dto = InteractionDtoUtils.newInteractionDto(            // <.>
-                    execution, InteractionDtoUtils.Strategy.DEEP);
-        executions.add(dto);
-    }
-    // ...
-//end::class[]
-
-//tag::demo[]
-    public Stream<InteractionDto> streamInteractionDtos() {
-        return executions.stream();
-    }
-
-    public void clear() {
-        executions.clear();
-    }
-//end::demo[]
-
-    @Override
-    public void publish(PublishedObjects publishedObjects) {
-    }
-
-//tag::class[]
-}
-//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_changes/ExposeCapturedChanges.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_changes/ExposeCapturedChanges.java
new file mode 100644
index 0000000..88d15db
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_changes/ExposeCapturedChanges.java
@@ -0,0 +1,9 @@
+package demoapp.dom.annotDomain._changes;
+
+/**
+ * Marker interface for mixins to contribute to.
+ */
+//tag::class[]
+public interface ExposeCapturedChanges {
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_changes/ExposeCapturedChanges_changes.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_changes/ExposeCapturedChanges_changes.java
new file mode 100644
index 0000000..858364e
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_changes/ExposeCapturedChanges_changes.java
@@ -0,0 +1,35 @@
+package demoapp.dom.annotDomain._changes;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Collection;
+import org.apache.isis.schema.chg.v2.ChangesDto;
+
+import lombok.RequiredArgsConstructor;
+import lombok.val;
+
+//tag::class[]
+@Collection
+@RequiredArgsConstructor
+public class ExposeCapturedChanges_changes {
+    // ...
+//end::class[]
+
+    private final ExposeCapturedChanges exposeCapturedChanges;
+
+//tag::class[]
+    public List<ChangesDto> coll() {
+        val list = new LinkedList<ChangesDto>();
+        publisherServiceToCaptureChangesInMemory
+                .streamPublishedObjects()
+                .forEach(list::push);   // reverse order
+        return list;
+    }
+
+    @Inject
+    PublisherServiceToCaptureChangesInMemory publisherServiceToCaptureChangesInMemory;
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingVm_clearPublishedObjects.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_changes/ExposeCapturedChanges_clear.java
similarity index 59%
rename from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingVm_clearPublishedObjects.java
rename to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_changes/ExposeCapturedChanges_clear.java
index d33097d..3af86fa 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingVm_clearPublishedObjects.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_changes/ExposeCapturedChanges_clear.java
@@ -1,4 +1,4 @@
-package demoapp.dom.annotDomain.DomainObject.publishing.spiimpl;
+package demoapp.dom.annotDomain._changes;
 
 import javax.inject.Inject;
 
@@ -10,26 +10,26 @@ import demoapp.dom.annotDomain.DomainObject.publishing.DomainObjectPublishingVm;
 //tag::class[]
 @Action(
     semantics = SemanticsOf.IDEMPOTENT
-    , associateWith = "publishedObjects"
+    , associateWith = "changes"
 )
-public class DomainObjectPublishingVm_clearPublishedObjects {
+public class ExposeCapturedChanges_clear {
     // ...
 //end::class[]
 
     private final DomainObjectPublishingVm domainObjectPublishingVm;
 
-    public DomainObjectPublishingVm_clearPublishedObjects(DomainObjectPublishingVm domainObjectPublishingVm) {
+    public ExposeCapturedChanges_clear(DomainObjectPublishingVm domainObjectPublishingVm) {
         this.domainObjectPublishingVm = domainObjectPublishingVm;
     }
 
 
     //tag::class[]
     public DomainObjectPublishingVm act() {
-        publisherServiceSpiForDomainObject.clear();
+        publisherServiceToCaptureChangesInMemory.clear();
         return domainObjectPublishingVm;
     }
 
     @Inject
-    PublisherServiceSpiForDomainObject publisherServiceSpiForDomainObject;
+    PublisherServiceToCaptureChangesInMemory publisherServiceToCaptureChangesInMemory;
 }
 //end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/PublisherServiceSpiForDomainObject.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_changes/PublisherServiceToCaptureChangesInMemory.java
similarity index 87%
rename from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/PublisherServiceSpiForDomainObject.java
rename to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_changes/PublisherServiceToCaptureChangesInMemory.java
index 265f574..9523966 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/PublisherServiceSpiForDomainObject.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_changes/PublisherServiceToCaptureChangesInMemory.java
@@ -1,4 +1,4 @@
-package demoapp.dom.annotDomain.DomainObject.publishing.spiimpl;
+package demoapp.dom.annotDomain._changes;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -15,7 +15,7 @@ import lombok.val;
 
 //tag::class[]
 @Service
-public class PublisherServiceSpiForDomainObject implements PublisherService {
+public class PublisherServiceToCaptureChangesInMemory implements PublisherService {
 
     private final List<ChangesDto> publishedObjects = new ArrayList<>();
 
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_commands/ExposePersistedCommands.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_commands/ExposePersistedCommands.java
new file mode 100644
index 0000000..4c70430
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_commands/ExposePersistedCommands.java
@@ -0,0 +1,24 @@
+package demoapp.dom.annotDomain._commands;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Collection;
+import org.apache.isis.applib.annotation.CollectionLayout;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
+
+import lombok.RequiredArgsConstructor;
+import lombok.val;
+
+import demoapp.dom.annotDomain.Action.command.ActionCommandJdo;
+
+/**
+ * Marker interface for mixins to contribute to.
+ */
+//tag::class[]
+public interface ExposePersistedCommands {
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_commands/ExposePersistedCommands_commands.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_commands/ExposePersistedCommands_commands.java
new file mode 100644
index 0000000..91f6431
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_commands/ExposePersistedCommands_commands.java
@@ -0,0 +1,33 @@
+package demoapp.dom.annotDomain._commands;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Collection;
+import org.apache.isis.applib.annotation.CollectionLayout;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
+
+import lombok.RequiredArgsConstructor;
+import lombok.val;
+
+//tag::class[]
+@Collection
+@CollectionLayout(defaultView = "table")
+@RequiredArgsConstructor
+public class ExposePersistedCommands_commands {
+    // ...
+//end::class[]
+    private final ExposePersistedCommands exposePersistedCommands;
+
+    //tag::class[]
+    public List<CommandJdo> coll() {
+        val list = new LinkedList<CommandJdo>();
+        return commandJdoRepository.findCompleted();
+    }
+
+    @Inject CommandJdoRepository commandJdoRepository;
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/ExposeCapturedInteractions.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/ExposeCapturedInteractions.java
new file mode 100644
index 0000000..1aa9f06
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/ExposeCapturedInteractions.java
@@ -0,0 +1,9 @@
+package demoapp.dom.annotDomain._interactions;
+
+/**
+ * Marker interface for mixins to contribute to.
+ */
+//tag::class[]
+public interface ExposeCapturedInteractions {
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/ExposeCapturedInteractions_clear.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/ExposeCapturedInteractions_clear.java
new file mode 100644
index 0000000..229418c
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/ExposeCapturedInteractions_clear.java
@@ -0,0 +1,31 @@
+package demoapp.dom.annotDomain._interactions;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.SemanticsOf;
+
+import lombok.RequiredArgsConstructor;
+
+//tag::class[]
+@Action(
+    semantics = SemanticsOf.IDEMPOTENT
+    , associateWith = "interactions"
+)
+@RequiredArgsConstructor
+public class ExposeCapturedInteractions_clear {
+    // ...
+//end::class[]
+
+    private final ExposeCapturedInteractions exposeCapturedInteractions;
+
+//tag::class[]
+    public ExposeCapturedInteractions act() {
+        publisherServiceToCaptureInteractionsInMemory.clear();
+        return exposeCapturedInteractions;
+    }
+
+    @Inject
+    PublisherServiceToCaptureInteractionsInMemory publisherServiceToCaptureInteractionsInMemory;
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/ExposeCapturedInteractions_interactions.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/ExposeCapturedInteractions_interactions.java
new file mode 100644
index 0000000..522437d
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/ExposeCapturedInteractions_interactions.java
@@ -0,0 +1,35 @@
+package demoapp.dom.annotDomain._interactions;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Collection;
+
+import lombok.RequiredArgsConstructor;
+import lombok.val;
+
+//tag::class[]
+@Collection
+@RequiredArgsConstructor
+public class ExposeCapturedInteractions_interactions {
+    // ...
+//end::class[]
+
+    private final ExposeCapturedInteractions exposeCapturedInteractions;
+
+//tag::class[]
+    public List<InteractionDtoVm> coll() {
+        val list = new LinkedList<InteractionDtoVm>();
+        publisherServiceToCaptureInteractionsInMemory
+                .streamInteractionDtos()
+                .map(InteractionDtoVm::new)
+                .forEach(list::push);   // reverse order
+        return list;
+    }
+
+    @Inject
+    PublisherServiceToCaptureInteractionsInMemory publisherServiceToCaptureInteractionsInMemory;
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/InteractionDtoVm.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/InteractionDtoVm.java
new file mode 100644
index 0000000..a5c6f5c
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/InteractionDtoVm.java
@@ -0,0 +1,62 @@
+package demoapp.dom.annotDomain._interactions;
+
+import java.text.SimpleDateFormat;
+
+import org.apache.isis.applib.ViewModel;
+import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.LabelPosition;
+import org.apache.isis.applib.annotation.Nature;
+import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.annotation.PropertyLayout;
+import org.apache.isis.applib.services.urlencoding.UrlEncodingService;
+import org.apache.isis.applib.util.TitleBuffer;
+import org.apache.isis.applib.util.schema.InteractionDtoUtils;
+import org.apache.isis.core.runtimeservices.urlencoding.UrlEncodingServiceWithCompression;
+import org.apache.isis.schema.ixn.v2.InteractionDto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.val;
+
+//tag::class[]
+@DomainObject(
+    objectType = "demo.InteractionDtoVm"
+    , nature = Nature.VIEW_MODEL
+)
+@NoArgsConstructor
+@AllArgsConstructor
+public class InteractionDtoVm implements ViewModel {
+
+    private final static UrlEncodingService encodingService = new UrlEncodingServiceWithCompression();
+
+    public String title() {
+        // nb: not thread-safe
+        // formats defined in https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
+        val format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+
+        val buf = new TitleBuffer();
+        buf.append(format.format(getInteractionDto().getExecution().getMetrics().getTimings().getStartedAt().toString()));
+        buf.append(" ").append(getInteractionDto().getExecution().getLogicalMemberIdentifier());
+        return buf.toString();
+    }
+
+
+    @Property
+    @PropertyLayout(labelPosition = LabelPosition.NONE)
+    @Getter @Setter
+    private InteractionDto interactionDto;
+
+    @Override
+    public String viewModelMemento() {
+        return encodingService.encodeString(InteractionDtoUtils.toXml(interactionDto));
+    }
+
+    @Override
+    public void viewModelInit(String memento) {
+        interactionDto =  InteractionDtoUtils.fromXml(encodingService.decodeToString(memento));
+    }
+
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/InteractionDtoVm.layout.xml
similarity index 97%
copy from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo.layout.xml
copy to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/InteractionDtoVm.layout.xml
index a9500e1..c18182f 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo.layout.xml
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/InteractionDtoVm.layout.xml
@@ -27,7 +27,7 @@
 			</bs3:row>
 			<bs3:row>
 				<bs3:col span="12">
-					<cpt:collection id="interactionExecutions"/>
+					<cpt:collection id="interactions"/>
 				</bs3:col>
 			</bs3:row>
 			<bs3:row>
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/spiimpl/PublisherServiceSpiForActions.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/PublisherServiceToCaptureInteractionsInMemory.java
similarity index 89%
rename from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/spiimpl/PublisherServiceSpiForActions.java
rename to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/PublisherServiceToCaptureInteractionsInMemory.java
index 79500ad..8e4badd 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/spiimpl/PublisherServiceSpiForActions.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/_interactions/PublisherServiceToCaptureInteractionsInMemory.java
@@ -1,4 +1,4 @@
-package demoapp.dom.annotDomain.Action.publishing.spiimpl;
+package demoapp.dom.annotDomain._interactions;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -16,7 +16,7 @@ import lombok.val;
 
 //tag::class[]
 @Service
-public class PublisherServiceSpiForActions implements PublisherService {
+public class PublisherServiceToCaptureInteractionsInMemory implements PublisherService {
 
     private final List<InteractionDto> executions = new ArrayList<>();
 
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/homepage/DemoHomePage.java b/examples/demo/domain/src/main/java/demoapp/dom/homepage/DemoHomePage.java
index f932c04..cd2280b 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/homepage/DemoHomePage.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/homepage/DemoHomePage.java
@@ -19,10 +19,12 @@
 package demoapp.dom.homepage;
 
 import javax.inject.Inject;
+import javax.inject.Provider;
 
 import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.applib.annotation.HomePage;
 import org.apache.isis.applib.annotation.Nature;
+import org.apache.isis.applib.services.scratchpad.Scratchpad;
 import org.apache.isis.applib.services.user.UserService;
 import org.apache.isis.valuetypes.asciidoc.applib.value.AsciiDoc;
 
@@ -31,8 +33,8 @@ import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
 
 //tag::class[]
 @DomainObject(
-        nature=Nature.VIEW_MODEL
-        , objectType = "demo.Homepage"
+    nature=Nature.VIEW_MODEL,
+    objectType = "demo.Homepage"
 )
 @HomePage                                                       // <.>
 public class DemoHomePage
@@ -46,10 +48,7 @@ public class DemoHomePage
         return asciiDocReaderService.readFor(this, "welcome");
     }
 
-    @Inject
-    UserService userService;                                    // <.>
-
-    @Inject
-    AsciiDocReaderService asciiDocReaderService;
+    @Inject UserService userService;                            // <.>
+    @Inject AsciiDocReaderService asciiDocReaderService;
 }
 //end::class[]
diff --git a/examples/demo/domain/src/main/resources/application.yml b/examples/demo/domain/src/main/resources/application.yml
index f8abeb7..2134d0c 100644
--- a/examples/demo/domain/src/main/resources/application.yml
+++ b/examples/demo/domain/src/main/resources/application.yml
@@ -137,3 +137,8 @@ vaadin:
   urlMapping: "/vaadin/*"
   servlet:
       productionMode: true
+
+management:
+  endpoint:
+    health:
+      enabled: true
diff --git a/examples/demo/vaadin/src/main/java/demoapp/webapp/vaadin/DemoAppVaadin.java b/examples/demo/vaadin/src/main/java/demoapp/webapp/vaadin/DemoAppVaadin.java
index 5997e15..6b9b4a4 100644
--- a/examples/demo/vaadin/src/main/java/demoapp/webapp/vaadin/DemoAppVaadin.java
+++ b/examples/demo/vaadin/src/main/java/demoapp/webapp/vaadin/DemoAppVaadin.java
@@ -49,7 +49,7 @@ import demoapp.web._infra.utils.ThereCanBeOnlyOne;
     // WICKET INTEGRATION ... to allow side by side comparison
     IsisModuleViewerWicketViewer.class, // wicket viewer
     IsisModuleValSseUiWkt.class, // server sent events
-    IsisModuleValAsciidocUiWkt.class, // ascii-doc rendering support (for Wicket)
+    IsisModuleValAsciidocUiVaa.class, // ascii-doc rendering support (for Wicket)
   
 })
 public class DemoAppVaadin extends SpringBootServletInitializer {
diff --git a/examples/demo/web/src/main/java/demoapp/web/quartz/BackgroundCommandsQuartzJobConfigurerModule.java b/examples/demo/web/src/main/java/demoapp/web/quartz/BackgroundCommandsQuartzJobConfigurerModule.java
index 7144c2f..86ec11b 100644
--- a/examples/demo/web/src/main/java/demoapp/web/quartz/BackgroundCommandsQuartzJobConfigurerModule.java
+++ b/examples/demo/web/src/main/java/demoapp/web/quartz/BackgroundCommandsQuartzJobConfigurerModule.java
@@ -2,29 +2,18 @@ package demoapp.web.quartz;
 
 import javax.inject.Inject;
 
-import org.quartz.Job;
-import org.quartz.JobBuilder;
-import org.quartz.JobDataMap;
 import org.quartz.JobDetail;
-import org.quartz.JobKey;
 import org.quartz.SimpleTrigger;
 import org.quartz.Trigger;
-import org.quartz.spi.TriggerFiredBundle;
-import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
 import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.core.io.ClassPathResource;
 import org.springframework.scheduling.quartz.JobDetailFactoryBean;
 import org.springframework.scheduling.quartz.SchedulerFactoryBean;
 import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
 import org.springframework.scheduling.quartz.SpringBeanJobFactory;
-import org.springframework.stereotype.Service;
 
-import org.apache.isis.extensions.quartz.jobs.RunBackgroundCommandsJob;
+import org.apache.isis.extensions.quartz.jobs.DemoJob;
 
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
@@ -36,7 +25,7 @@ public class BackgroundCommandsQuartzJobConfigurerModule {
     @Bean
     public JobDetailFactoryBean jobDetail() {
         val jobDetailFactory = new JobDetailFactoryBean();
-        jobDetailFactory.setJobClass(RunBackgroundCommandsJob.class);
+        jobDetailFactory.setJobClass(DemoJob.class);
         jobDetailFactory.setDescription("Run background commands");
         jobDetailFactory.setDurability(true);
         return jobDetailFactory;
diff --git a/examples/demo/wicket/src/main/resources/log4j2-spring.xml b/examples/demo/wicket/src/main/resources/log4j2-spring.xml
index 0c0e64c..2e788de 100644
--- a/examples/demo/wicket/src/main/resources/log4j2-spring.xml
+++ b/examples/demo/wicket/src/main/resources/log4j2-spring.xml
@@ -35,7 +35,7 @@ under the License.
 	
 		<!-- silence Wicket -->
 		<Logger name="org.apache.wicket.page.PartialPageUpdate" level="error" />
-	
+
 		<Logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
 		<Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
 		<Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
@@ -52,7 +52,10 @@ under the License.
 		<logger name="DataNucleus.Transaction" level="info"/>
 		<logger name="DataNucleus.Datastore.Schema" level="info"/>
 		<logger name="DataNucleus.Datastore.Native" level="info"/>
-		
+
+		<!-- debugging -->
+		<Logger name="org.apache.isis.applib.services.command.CommandServiceDefault" level="debug" />
+
 		<Root level="info">
 			<AppenderRef ref="Console" />
 		</Root>
diff --git a/examples/smoketests/stable/src/main/java/org/apache/isis/testdomain/conf/Configuration_headless.java b/examples/smoketests/stable/src/main/java/org/apache/isis/testdomain/conf/Configuration_headless.java
index df41ee8..fdda23b 100644
--- a/examples/smoketests/stable/src/main/java/org/apache/isis/testdomain/conf/Configuration_headless.java
+++ b/examples/smoketests/stable/src/main/java/org/apache/isis/testdomain/conf/Configuration_headless.java
@@ -139,12 +139,7 @@ public class Configuration_headless {
                         commandContext.setCommand(newCommand);
                         return newCommand;
                     });
-            final Command.Executor executor = command.getExecutor();
-            if(executor != Command.Executor.OTHER) {
-                return;
-            }
-            command.internal().setExecutor(Command.Executor.USER);
-            
+
             val interactionContext = interactionContextProvider.get();
             @SuppressWarnings("unused")
             final Interaction interaction = Optional.ofNullable(interactionContext.getInteraction())
diff --git a/extensions/core/command-log/impl/pom.xml b/extensions/core/command-log/impl/pom.xml
index b6d4d18..6bfbfa2 100644
--- a/extensions/core/command-log/impl/pom.xml
+++ b/extensions/core/command-log/impl/pom.xml
@@ -27,6 +27,23 @@
         <git-plugin.propertiesDir>org/apache/isis/extensions/commandlog/impl</git-plugin.propertiesDir>
     </properties>
 
+    <build>
+        <resources>
+            <resource>
+                <filtering>false</filtering>
+                <directory>src/main/resources</directory>
+            </resource>
+            <resource>
+                <filtering>false</filtering>
+                <directory>src/main/java</directory>
+                <includes>
+                    <!-- we include all .java too, so that we can reference it from the descriptions -->
+                    <include>**</include>
+                </includes>
+            </resource>
+        </resources>
+    </build>
+
     <dependencies>
 
         <dependency>
@@ -55,4 +72,4 @@
 
     </dependencies>
 
-</project>
+</project>
\ No newline at end of file
diff --git a/extensions/core/command-log/impl/src/main/java/META-INF/persistence.xml b/extensions/core/command-log/impl/src/main/java/META-INF/persistence.xml
index 7edf7e4..26b8ff5 100644
--- a/extensions/core/command-log/impl/src/main/java/META-INF/persistence.xml
+++ b/extensions/core/command-log/impl/src/main/java/META-INF/persistence.xml
@@ -14,5 +14,6 @@
     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
 
     <persistence-unit name="org-apache-isis-extensions-commandlog">
+        <class>org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo</class>
     </persistence-unit>
 </persistence>
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/IsisModuleExtCommandLogImpl.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/IsisModuleExtCommandLogImpl.java
index 21135fa..6d176a2 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/IsisModuleExtCommandLogImpl.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/IsisModuleExtCommandLogImpl.java
@@ -14,12 +14,11 @@ import org.apache.isis.testing.fixtures.applib.teardown.TeardownFixtureAbstract;
 @Configuration
 @Import({
         // @DomainService's
-        BackgroundCommandExecutionFromBackgroundCommandServiceJdo.class
-        , BackgroundCommandServiceJdo.class
-        , BackgroundCommandServiceJdoRepository.class
-        , CommandServiceJdo.class
-        , CommandJdoRepository.class
+        CommandJdoRepository.class
         , CommandServiceMenu.class
+
+        // @Service's
+        , CommandJdo.TableColumnOrderDefault.class
 })
 @ComponentScan(
         basePackageClasses= {
@@ -27,6 +26,18 @@ import org.apache.isis.testing.fixtures.applib.teardown.TeardownFixtureAbstract;
         })
 public class IsisModuleExtCommandLogImpl implements ModuleWithFixtures {
 
+    public abstract static class TitleUiEvent<S>
+            extends org.apache.isis.applib.events.ui.TitleUiEvent<S> { }
+
+    public abstract static class IconUiEvent<S>
+            extends org.apache.isis.applib.events.ui.IconUiEvent<S> { }
+
+    public abstract static class CssClassUiEvent<S>
+            extends org.apache.isis.applib.events.ui.CssClassUiEvent<S> { }
+
+    public abstract static class LayoutUiEvent<S>
+            extends org.apache.isis.applib.events.ui.LayoutUiEvent<S> { }
+
     public abstract static class ActionDomainEvent<S>
             extends org.apache.isis.applib.events.domain.ActionDomainEvent<S> { }
 
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo.java
index 7707434..0b3e6e2 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo.java
@@ -18,23 +18,24 @@
  */
 package org.apache.isis.extensions.commandlog.impl.jdo;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
 import java.math.BigDecimal;
-import java.math.RoundingMode;
 import java.sql.Timestamp;
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
 import java.util.function.Consumer;
-import java.util.stream.Collectors;
 
-import javax.inject.Inject;
 import javax.jdo.annotations.IdentityType;
 
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Service;
+
 import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.applib.annotation.DomainObjectLayout;
 import org.apache.isis.applib.annotation.Editing;
+import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.annotation.Property;
 import org.apache.isis.applib.annotation.PropertyLayout;
@@ -43,17 +44,21 @@ import org.apache.isis.applib.jaxb.JavaSqlXMLGregorianCalendarMarshalling;
 import org.apache.isis.applib.services.DomainChangeRecord;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.jaxb.JaxbService;
+import org.apache.isis.applib.services.conmap.command.UserDataKeys;
+import org.apache.isis.applib.services.tablecol.TableColumnOrderForCollectionTypeAbstract;
 import org.apache.isis.applib.types.MemberIdentifierType;
 import org.apache.isis.applib.util.ObjectContracts;
 import org.apache.isis.applib.util.TitleBuffer;
+import org.apache.isis.core.commons.internal.base._Strings;
 import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
-import org.apache.isis.extensions.commandlog.impl.api.UserDataKeys;
+import org.apache.isis.extensions.commandlog.impl.util.BigDecimalUtils;
+import org.apache.isis.extensions.commandlog.impl.util.StringUtils;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.cmd.v2.MapDto;
 
 import lombok.Getter;
+import lombok.NoArgsConstructor;
 import lombok.Setter;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
@@ -75,10 +80,10 @@ import lombok.extern.log4j.Log4j2;
         table = "Command")
 @javax.jdo.annotations.Queries( {
     @javax.jdo.annotations.Query(
-            name="findByUniqueId",
+            name="findByUniqueIdStr",
             value="SELECT "
                     + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
-                    + "WHERE uniqueId == :uniqueId "),
+                    + "WHERE uniqueIdStr == :uniqueIdStr "),
     @javax.jdo.annotations.Query(
             name="findByParent",
             value="SELECT "
@@ -95,14 +100,13 @@ import lombok.extern.log4j.Log4j2;
             value="SELECT "
                     + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
                     + "WHERE completedAt != null "
-                    + "&& executeIn == 'FOREGROUND' "
                     + "ORDER BY this.timestamp DESC"),
     @javax.jdo.annotations.Query(
             name="findRecentByTarget",
             value="SELECT "
                     + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
                     + "WHERE targetStr == :targetStr "
-                    + "ORDER BY this.timestamp DESC, uniqueId DESC "
+                    + "ORDER BY this.timestamp DESC, uniqueIdStr DESC "
                     + "RANGE 0,30"),
     @javax.jdo.annotations.Query(
             name="findByTargetAndTimestampBetween",
@@ -157,18 +161,17 @@ import lombok.extern.log4j.Log4j2;
                     + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
                     + "ORDER BY this.timestamp DESC"),
     @javax.jdo.annotations.Query(
-            name="findRecentByUser",
+            name="findRecentByUsername",
             value="SELECT "
                     + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
-                    + "WHERE user == :user "
+                    + "WHERE username == :username "
                     + "ORDER BY this.timestamp DESC "
                     + "RANGE 0,30"),
     @javax.jdo.annotations.Query(
             name="findFirst",
             value="SELECT "
                     + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
-                    + "WHERE timestamp   != null "
-                    + "   && startedAt   != null "
+                    + "WHERE startedAt   != null "
                     + "   && completedAt != null "
                     + "ORDER BY this.timestamp ASC "
                     + "RANGE 0,2"),
@@ -182,91 +185,89 @@ import lombok.extern.log4j.Log4j2;
                     + "   && startedAt != null "
                     + "   && completedAt != null "
                     + "ORDER BY this.timestamp ASC"),
+    // most recent replayable command previously replicated from primary to
+    // secondary.  This should always exist except for the very first times
+    // (after restored the prod DB to secondary).
     @javax.jdo.annotations.Query(
-            name="findReplayableHwm",
+            name="findReplayedHwm",
             value="SELECT "
                     + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
-                    + "WHERE executeIn == 'REPLAYABLE' "
+                    + "WHERE (replayState == 'OK' || replayState == 'FAILED')"
                     + "ORDER BY this.timestamp DESC "
-                    + "RANGE 0,2"),
-        // this should be RANGE 0,1 but results in DataNucleus submitting "FETCH NEXT ROW ONLY"
-        // which SQL Server doesn't understand.  However, as workaround, SQL Server *does* understand FETCH NEXT 2 ROWS ONLY
+                    + "RANGE 0,2"), // this should be RANGE 0,1 but results in DataNucleus submitting "FETCH NEXT ROW ONLY"
+                                    // which SQL Server doesn't understand.  However, as workaround, SQL Server *does* understand FETCH NEXT 2 ROWS ONLY
+    // otherwise, the most recent completed command, as queried on the
+    // secondary, corresponding to the last command run on primary before the
+    // production database was restored to the secondary
     @javax.jdo.annotations.Query(
-            name="findForegroundHwm",
+            name="findHwm",
             value="SELECT "
                     + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
-                    + "WHERE executeIn == 'FOREGROUND' "
-                    + "   && startedAt   != null "
+                    + "WHERE startedAt   != null "
                     + "   && completedAt != null "
                     + "ORDER BY this.timestamp DESC "
                     + "RANGE 0,2"),
         // this should be RANGE 0,1 but results in DataNucleus submitting "FETCH NEXT ROW ONLY"
         // which SQL Server doesn't understand.  However, as workaround, SQL Server *does* understand FETCH NEXT 2 ROWS ONLY
-    @javax.jdo.annotations.Query(
-            name="findBackgroundCommandsNotYetStarted",
-            value="SELECT "
-                    + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
-                    + "WHERE executeIn == 'BACKGROUND' "
-                    + "   && startedAt == null "
-                    + "ORDER BY this.timestamp ASC "),
-        @javax.jdo.annotations.Query(
-                name="findReplayableInErrorMostRecent",
-                value="SELECT "
-                        + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
-                        + "WHERE executeIn   == 'REPLAYABLE' "
-                        + "  && (replayState != 'PENDING' || "
-                        + "      replayState != 'OK'      || "
-                        + "      replayState != 'EXCLUDED'   ) "
-                        + "ORDER BY this.timestamp DESC "
-                        + "RANGE 0,2"),
-    @javax.jdo.annotations.Query(
-            name="findReplayableMostRecentStarted",
-            value="SELECT "
-                    + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
-                    + "WHERE executeIn == 'REPLAYABLE' "
-                    + "   && startedAt != null "
-                    + "ORDER BY this.timestamp DESC "
-                    + "RANGE 0,20"),
+//    @javax.jdo.annotations.Query(
+//            name="findNotYetStarted",
+//            value="SELECT "
+//                    + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
+//                    + "WHERE startedAt == null "
+//                    + "ORDER BY this.timestamp ASC "),
+//        @javax.jdo.annotations.Query(
+//                name="findReplayableInErrorMostRecent",
+//                value="SELECT "
+//                        + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
+//                        + "WHERE replayState == 'FAILED' "
+//                        + "ORDER BY this.timestamp DESC "
+//                        + "RANGE 0,2"),
+//    @javax.jdo.annotations.Query(
+//            name="findReplayableMostRecentStarted",
+//            value="SELECT "
+//                    + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
+//                    + "WHERE replayState = 'PENDING' "
+//                    + "ORDER BY this.timestamp DESC "
+//                    + "RANGE 0,20"),
 })
 @javax.jdo.annotations.Indices({
-        @javax.jdo.annotations.Index(name = "CommandJdo_timestamp_e_s_IDX", members = {"timestamp", "executeIn", "startedAt"}),
-        @javax.jdo.annotations.Index(name = "CommandJdo_startedAt_e_c_IDX", members = {"startedAt", "executeIn", "completedAt"}),
+        @javax.jdo.annotations.Index(name = "CommandJdo__startedAt__timestamp__IDX", members = { "startedAt", "timestamp" }),
+        @javax.jdo.annotations.Index(name = "CommandJdo__timestamp__IDX", members = { "timestamp" }),
+//        @javax.jdo.annotations.Index(name = "CommandJdo__replayState__timestamp__startedAt_IDX", members = { "replayState", "timestamp", "startedAt"}),
+//        @javax.jdo.annotations.Index(name = "CommandJdo__replayState__startedAt__completedAt_IDX", members = {"startedAt", "replayState", "completedAt"}),
 })
 @DomainObject(
         objectType = "isisExtensionsCommandLog.Command",
         editing = Editing.DISABLED
 )
-@DomainObjectLayout(named = "Command")
+@DomainObjectLayout(
+        named = "Command",
+        titleUiEvent = CommandJdo.TitleUiEvent.class,
+        iconUiEvent = CommandJdo.IconUiEvent.class,
+        cssClassUiEvent = CommandJdo.CssClassUiEvent.class,
+        layoutUiEvent = CommandJdo.LayoutUiEvent.class
+)
 @Log4j2
+@NoArgsConstructor
 public class CommandJdo
         implements DomainChangeRecord, Comparable<CommandJdo> {
 
+    public static class TitleUiEvent extends IsisModuleExtCommandLogImpl.TitleUiEvent<CommandJdo> { }
+    public static class IconUiEvent extends IsisModuleExtCommandLogImpl.IconUiEvent<CommandJdo> { }
+    public static class CssClassUiEvent extends IsisModuleExtCommandLogImpl.CssClassUiEvent<CommandJdo> { }
+    public static class LayoutUiEvent extends IsisModuleExtCommandLogImpl.LayoutUiEvent<CommandJdo> { }
 
     public static abstract class PropertyDomainEvent<T> extends IsisModuleExtCommandLogImpl.PropertyDomainEvent<CommandJdo, T> { }
     public static abstract class CollectionDomainEvent<T> extends IsisModuleExtCommandLogImpl.CollectionDomainEvent<CommandJdo, T> { }
     public static abstract class ActionDomainEvent extends IsisModuleExtCommandLogImpl.ActionDomainEvent<CommandJdo> { }
 
-    public CommandJdo() {
-        this(UUID.randomUUID());
-    }
-
-    private CommandJdo(final UUID uniqueId) {
-        super();
-        this.uniqueId = uniqueId;
-    }
-
     /**
      * Intended for use on primary system.
      *
      * @param command
-     * @param commandJdoRepository
      */
-    public CommandJdo(
-            final Command command
-            , final CommandJdoRepository commandJdoRepository) {
-        this();
-
-        setUniqueId(command.getUniqueId());
+    public CommandJdo(final Command command) {
+        setUniqueIdStr(command.getUniqueId().toString());
         setUsername(command.getUsername());
         setTimestamp(command.getTimestamp());
 
@@ -274,11 +275,6 @@ public class CommandJdo
         setTarget(command.getTarget());
         setLogicalMemberIdentifier(command.getLogicalMemberIdentifier());
 
-        val parent = command.getParent();
-        if(parent != null) {
-            setParent(commandJdoRepository.findByUniqueId(parent.getUniqueId()).orElse(null));
-        }
-
         setStartedAt(command.getStartedAt());
         setCompletedAt(command.getCompletedAt());
 
@@ -298,9 +294,8 @@ public class CommandJdo
      * @param targetIndex - if the command represents a bulk action, then it is flattened out when replayed; this indicates which target to execute against.
      */
     public CommandJdo(final CommandDto commandDto, final ReplayState replayState, final int targetIndex) {
-        this();
 
-        setUniqueId(UUID.fromString(commandDto.getTransactionId()));
+        setUniqueIdStr(commandDto.getTransactionId());
         setUsername(commandDto.getUser());
         setTimestamp(JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(commandDto.getTimestamp()));
 
@@ -314,19 +309,21 @@ public class CommandJdo
         setStartedAt(JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(commandDto.getTimings().getStartedAt()));
         setCompletedAt(JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(commandDto.getTimings().getCompletedAt()));
 
-        set(commandDto, UserDataKeys.RESULT, value -> setResult(Bookmark.parse(value).orElse(null)));
-        set(commandDto, UserDataKeys.EXCEPTION, this::setException);
+        copyOver(commandDto, UserDataKeys.RESULT, value -> this.setResult(Bookmark.parse(value).orElse(null)));
+        copyOver(commandDto, UserDataKeys.EXCEPTION, this::setException);
 
         setReplayState(replayState);
     }
 
-    private void set(CommandDto commandDto, String key, Consumer<String> consumer) {
+    static void copyOver(
+            final CommandDto commandDto,
+            final String key, final Consumer<String> consume) {
         commandDto.getUserData().getEntry()
                 .stream()
-                .filter(x -> Objects.equals(x.getKey(), UserDataKeys.RESULT))
+                .filter(x -> Objects.equals(x.getKey(), key))
                 .map(MapDto.Entry::getValue)
                 .findFirst()
-                .ifPresent(consumer::accept);
+                .ifPresent(consume);
     }
 
     public String title() {
@@ -341,12 +338,21 @@ public class CommandJdo
     }
 
 
-    public static class UniqueIdDomainEvent extends PropertyDomainEvent<UUID> { }
+    public static class UniqueIdDomainEvent extends PropertyDomainEvent<String> { }
+    /**
+     * Implementation note: persisted as a string rather than a UUID as fails
+     * to persist if using h2 (perhaps would need to be mapped differently).
+     * @see <a href="https://www.datanucleus.org/products/accessplatform/jdo/mapping.html#_other_types">DN documentation</a>.
+     */
+    @javax.jdo.annotations.PrimaryKey
     @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="false", length = 36)
+    @javax.jdo.annotations.Column(allowsNull="false", name = "uniqueId", length = 36)
     @Property(domainEvent = UniqueIdDomainEvent.class)
+    @PropertyLayout(named = "UniqueId")
     @Getter @Setter
-    private UUID uniqueId;
+    private String uniqueIdStr;
+    @Programmatic
+    public UUID getUniqueId() {return UUID.fromString(getUniqueIdStr());}
 
 
     public static class UsernameDomainEvent extends PropertyDomainEvent<String> { }
@@ -461,7 +467,7 @@ public class CommandJdo
     @javax.validation.constraints.Digits(integer=5, fraction=3)
     @Property(domainEvent = DurationDomainEvent.class)
     public BigDecimal getDuration() {
-        return durationBetween(getStartedAt(), getCompletedAt());
+        return BigDecimalUtils.durationBetween(getStartedAt(), getCompletedAt());
     }
 
 
@@ -482,7 +488,7 @@ public class CommandJdo
         if(getCompletedAt() == null) {
             return "";
         }
-        if(getException() != null) {
+        if(!_Strings.isNullOrEmpty(getException())) {
             return "EXCEPTION";
         }
         if(getResult() != null) {
@@ -519,10 +525,7 @@ public class CommandJdo
         this.exception = exception;
     }
     public void setException(final Throwable exception) {
-        val stackTraceStr =
-                _Exceptions.streamStacktraceLines(exception, 1000)
-                .collect(Collectors.joining("\n"));
-        setException(stackTraceStr);
+        setException(_Exceptions.asStacktrace(exception));
     }
 
     public static class IsCausedExceptionDomainEvent extends PropertyDomainEvent<Boolean> { }
@@ -535,6 +538,28 @@ public class CommandJdo
 
 
     @Override
+    public String getPreValue() {
+        return null;
+    }
+
+    @Override
+    public String getPostValue() {
+        return null;
+    }
+
+
+    public void saveAnalysis(String analysis) {
+        if (analysis == null) {
+            setReplayState(ReplayState.OK);
+        } else {
+            setReplayState(ReplayState.FAILED);
+            setReplayStateFailureReason(StringUtils.trimmed(analysis, 255));
+        }
+
+    }
+
+
+    @Override
     public String toString() {
         return ObjectContracts
                 .toString("uniqueId", CommandJdo::getUniqueId)
@@ -552,38 +577,29 @@ public class CommandJdo
         return this.getTimestamp().compareTo(other.getTimestamp());
     }
 
+    @Service
+    @Order(OrderPrecedence.LATE - 10) // before the framework's own default.
+    public static class TableColumnOrderDefault extends TableColumnOrderForCollectionTypeAbstract<CommandJdo> {
 
-    /**
-     * @return in seconds, to 3 decimal places.
-     */
-    private static BigDecimal durationBetween(Timestamp startedAt, Timestamp completedAt) {
-        if (completedAt == null) {
-            return null;
-        } else {
-            long millis = completedAt.getTime() - startedAt.getTime();
-            return toSeconds(millis);
-        }
-    }
-
-    private static final BigDecimal DIVISOR = new BigDecimal(1000);
-
-    private static BigDecimal toSeconds(long millis) {
-        return new BigDecimal(millis)
-                    .divide(DIVISOR, RoundingMode.HALF_EVEN)
-                    .setScale(3, RoundingMode.HALF_EVEN);
-    }
+        public TableColumnOrderDefault() { super(CommandJdo.class); }
 
+        @Override
+        protected List<String> orderParented(Object parent, String collectionId, List<String> propertyIds) {
+            return ordered(propertyIds);
+        }
 
-    @Override
-    public String getPreValue() {
-        return null;
-    }
+        @Override
+        protected List<String> orderStandalone(List<String> propertyIds) {
+            return ordered(propertyIds);
+        }
 
-    @Override
-    public String getPostValue() {
-        return null;
+        private List<String> ordered(List<String> propertyIds) {
+            return Arrays.asList(
+                "timestamp", "target", "commandDto", "targetMember", "username", "complete", "resultSummary", "uniqueIdStr"
+            );
+        }
     }
 
-    @Inject JaxbService jaxbService;
 
 }
+
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdoRepository.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdoRepository.java
index 37b021c..6bd6a4f 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdoRepository.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdoRepository.java
@@ -26,9 +26,11 @@ import java.util.Optional;
 import java.util.UUID;
 
 
+import javax.annotation.Nullable;
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Provider;
+import javax.jdo.JDOQLTypedQuery;
 
 import org.joda.time.LocalDate;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -67,7 +69,8 @@ import lombok.extern.log4j.Log4j2;
 public class CommandJdoRepository {
 
     public List<CommandJdo> findByFromAndTo(
-            final LocalDate from, final LocalDate to) {
+            @Nullable final LocalDate from,
+            @Nullable final LocalDate to) {
         final Timestamp fromTs = toTimestampStartOfDayWithOffset(from, 0);
         final Timestamp toTs = toTimestampStartOfDayWithOffset(to, 1);
         
@@ -97,12 +100,12 @@ public class CommandJdoRepository {
     }
 
 
-    public Optional<CommandJdo> findByUniqueId(final UUID transactionId) {
+    public Optional<CommandJdo> findByUniqueId(final UUID uniqueId) {
         persistCurrentCommandIfRequired();
         return repositoryService.firstMatch(
                 new QueryDefault<>(CommandJdo.class,
-                        "findByUniqueId",
-                        "uniqueId", transactionId));
+                        "findByUniqueIdStr",
+                        "uniqueIdStr", uniqueId.toString()));
     }
 
     public List<CommandJdo> findByParent(final CommandJdo parent) {
@@ -132,7 +135,11 @@ public class CommandJdoRepository {
             return;
         } 
         final Command command = commandContextProvider.get().getCommand();
-        final CommandJdo commandJdo = new CommandJdo(command, this);
+        val systemStateChanged = command.isSystemStateChanged();
+        if(!systemStateChanged) {
+            return;
+        }
+        final CommandJdo commandJdo = new CommandJdo(command);
         repositoryService.persist(commandJdo);
     }
 
@@ -181,46 +188,62 @@ public class CommandJdoRepository {
     }
 
 
-    public List<CommandJdo> findRecentByUser(final String user) {
+    public List<CommandJdo> findRecentByUsername(final String username) {
         return repositoryService.allMatches(
-                new QueryDefault<>(CommandJdo.class, "findRecentByUser", "user", user));
+                new QueryDefault<>(
+                        CommandJdo.class,
+                        "findRecentByUsername",
+                        "username", username));
     }
 
 
     public List<CommandJdo> findRecentByTarget(final Bookmark target) {
         final String targetStr = target.toString();
         return repositoryService.allMatches(
-                new QueryDefault<>(CommandJdo.class, "findRecentByTarget", "targetStr", targetStr));
+                new QueryDefault<>(
+                        CommandJdo.class,
+                        "findRecentByTarget",
+                        "targetStr", targetStr));
     }
 
 
     /**
-     * Intended to support the replay of commands on a slave instance of the application.
+     * Intended to support the replay of commands on a seconadry instance of
+     * the application.
      *
-     * This finder returns all (completed) {@link CommandJdo}s started after the command with the specified
-     * transaction Id.  The number of commands returned can be limited so that they can be applied in batches.
+     * This finder returns all (completed) {@link CommandJdo}s started after
+     * the command with the specified uniqueId.  The number of commands
+     * returned can be limited so that they can be applied in batches.
      *
-     * If the provided transactionId is null, then only a single {@link CommandJdo command} is returned.  This is
-     * intended to support the case when the slave does not yet have any {@link CommandJdo command}s replicated.
-     * In practice this is unlikely; typically we expect that the slave will be set up to run against a copy of the
-     * master instance's DB (restored from a backup), in which case there will already be a {@link CommandJdo command}
-     * representing the current high water mark on the slave.
+     * If the provided uniqueId is null, then only a single
+     * {@link CommandJdo command} is returned.  This is intended to support
+     * the case when the secondary does not yet have any
+     * {@link CommandJdo command}s replicated.  In practice this is unlikely;
+     * typically we expect that the secondary will be set up to run against a
+     * copy of the primary instance's DB (restored from a backup), in which
+     * case there will already be a {@link CommandJdo command} representing the
+     * current high water mark on the slave.
      *
-     * If the transaction id is not null but the corresponding {@link CommandJdo command} is not found, then
-     * <tt>null</tt> is returned. In the replay scenario the caller will probably interpret this as an error because
-     * it means that the high water mark on the slave is inaccurate, referring to a non-existent
-     * {@link CommandJdo command} on the master.
+     * If the unique id is not null but the corresponding
+     * {@link CommandJdo command} is not found, then <tt>null</tt> is returned.
+     * In the replay scenario the caller will probably interpret this as an
+     * error because it means that the high water mark on the secondary is
+     * inaccurate, referring to a non-existent {@link CommandJdo command} on
+     * the primary.
      *
-     * @param transactionId - the identifier of the {@link CommandJdo command} being the replay hwm (using {@link #findReplayHwm()} on the slave), or null if no HWM was found there.
-     * @param batchSize - to restrict the number returned (so that replay commands can be batched).
+     * @param uniqueId - the identifier of the {@link CommandJdo command} being
+     *                   the replay hwm (using {@link #findReplayHwm()} on the
+     *                   secondary), or null if no HWM was found there.
+     * @param batchSize - to restrict the number returned (so that replay
+     *                   commands can be batched).
      *
      * @return
      */
-    public List<CommandJdo> findSince(final UUID transactionId, final Integer batchSize) {
-        if(transactionId == null) {
+    public List<CommandJdo> findSince(final UUID uniqueId, final Integer batchSize) {
+        if(uniqueId == null) {
             return findFirst();
         }
-        final CommandJdo from = findByTransactionIdElseNull(transactionId);
+        final CommandJdo from = findByUniqueIdElseNull(uniqueId);
         if(from == null) {
             return null;
         }
@@ -236,17 +259,19 @@ public class CommandJdoRepository {
     }
 
 
-    private CommandJdo findByTransactionIdElseNull(final UUID transactionId) {
-        var q = isisJdoSupport.newTypesafeQuery(CommandJdo.class);
+    private CommandJdo findByUniqueIdElseNull(final UUID uniqueId) {
+        val tsq = isisJdoSupport.newTypesafeQuery(CommandJdo.class);
         val cand = QCommandJdo.candidate();
-        q = q.filter(
-                cand.transactionId.eq(q.parameter("transactionId", UUID.class))
+        val q = tsq.filter(
+                cand.uniqueIdStr.eq(tsq.parameter("uniqueIdStr", String.class))
         );
-        q.setParameter("transactionId", transactionId);
+        q.setParameter("uniqueIdStr", uniqueId.toString());
         return q.executeUnique();
     }
 
-    private List<CommandJdo> findSince(final Timestamp timestamp, final Integer batchSize) {
+    private List<CommandJdo> findSince(
+            final Timestamp timestamp,
+            final Integer batchSize) {
         val q = new QueryDefault<>(
                 CommandJdo.class,
                 "findSince",
@@ -263,36 +288,49 @@ public class CommandJdoRepository {
     }
 
 
+    /**
+     * The most recent replayable command previously replicated from primary to
+     * secondary.
+     *
+     * <p>
+     * This should always exist except for the very first times
+     * (after restored the prod DB to secondary).
+     * </p>
+     *
+     * <p>
+     * Otherwise, the most recent completed command, as queried on the
+     * secondary, corresponding to the last command run on primary before the
+     * production database was restored to the secondary
+     * </p>
+     */
     public CommandJdo findReplayHwm() {
 
-        // most recent replayable command, replicated from master to slave
-        // this may or may not
-        Optional<CommandJdo> replayableHwm = repositoryService.firstMatch(
-                new QueryDefault<>(CommandJdo.class, "findReplayableHwm"));
-
-        return replayableHwm
+        // most recent replayable command, replicated from primary to secondary
+        return repositoryService.firstMatch(
+                new QueryDefault<>(
+                        CommandJdo.class, "findReplayableHwm"))
                 .orElseGet(() -> {
-            // otherwise, the most recent completed command, run on the slave,
+            // otherwise, the most recent completed command, run on the secondary,
             // this corresponds to a command restored from a copy of
             // the production database
-            Optional<CommandJdo> restoredFromDbHwm = repositoryService.firstMatch(
-                    new QueryDefault<>(CommandJdo.class, "findForegroundHwm"));
 
-            return restoredFromDbHwm.orElse(null);
+            return repositoryService.firstMatch(
+                    new QueryDefault<>(CommandJdo.class, "findHwm"))
+                    .orElse(null);
         });
 
     }
 
 
-    public List<CommandJdo> findBackgroundCommandsNotYetStarted() {
+    public List<CommandJdo> findNotYetStarted() {
         return repositoryService.allMatches(
                 new QueryDefault<>(CommandJdo.class,
-                        "findBackgroundCommandsNotYetStarted"));
+                        "findNotYetStarted"));
     }
 
 
 
-    public List<CommandJdo> findReplayedOnSlave() {
+    public List<CommandJdo> findReplayedOnSecondary() {
         return repositoryService.allMatches(
                 new QueryDefault<>(CommandJdo.class, "findReplayableMostRecentStarted"));
     }
@@ -319,7 +357,7 @@ public class CommandJdoRepository {
 
         final CommandJdo commandJdo = new CommandJdo();
 
-        commandJdo.setUniqueId(UUID.fromString(dto.getTransactionId()));
+        commandJdo.setUniqueIdStr(dto.getTransactionId());
         commandJdo.setTimestamp(JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(dto.getTimestamp()));
         commandJdo.setUsername(dto.getUser());
 
@@ -340,7 +378,6 @@ public class CommandJdoRepository {
     }
 
 
-
     @Inject Provider<CommandContext> commandContextProvider;
     @Inject RepositoryService repositoryService;
     @Inject IsisJdoSupport_v3_2 isisJdoSupport;
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_childCommands.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_childCommands.java
index 2db6437..f16bc2b 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_childCommands.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_childCommands.java
@@ -26,8 +26,12 @@ import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
 
 
-@Collection(domainEvent = CommandJdo_childCommands.CollectionDomainEvent.class)
-@CollectionLayout(defaultView = "table")
+@Collection(
+    domainEvent = CommandJdo_childCommands.CollectionDomainEvent.class
+)
+@CollectionLayout(
+    defaultView = "table"
+)
 public class CommandJdo_childCommands {
 
     public static class CollectionDomainEvent
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_openResultObject.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_openResultObject.java
index 24689de..5394bc9 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_openResultObject.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_openResultObject.java
@@ -18,6 +18,8 @@
  */
 package org.apache.isis.extensions.commandlog.impl.jdo;
 
+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;
@@ -28,14 +30,14 @@ import org.apache.isis.applib.services.message.MessageService;
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
 
 @Action(
-    semantics = SemanticsOf.SAFE
-    , domainEvent = CommandJdo_openResultObject.ActionDomainEvent.class
-    , associateWith = "result"
+    semantics = SemanticsOf.SAFE,
+    domainEvent = CommandJdo_openResultObject.ActionDomainEvent.class,
+    associateWith = "result"
 )
 @ActionLayout(named = "Open")
 public class CommandJdo_openResultObject {
 
-    public static abstract class ActionDomainEvent
+    public static class ActionDomainEvent
             extends IsisModuleExtCommandLogImpl.ActionDomainEvent<CommandJdo_openResultObject> { }
 
     private final CommandJdo commandJdo;
@@ -64,12 +66,8 @@ public class CommandJdo_openResultObject {
         }
     }
 
-    @javax.inject.Inject
-    BookmarkService bookmarkService;
-
-    @javax.inject.Inject
-    MessageService messageService;
-
+    @Inject BookmarkService bookmarkService;
+    @Inject MessageService messageService;
 
 
 }
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_retry.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_retry.java
index d251482..b1ee0a4 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_retry.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_retry.java
@@ -25,6 +25,7 @@ import java.util.List;
 import javax.inject.Inject;
 
 import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.CommandReification;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.command.CommandContext;
@@ -39,6 +40,7 @@ import lombok.val;
 @Action(
     semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE
     , domainEvent = CommandJdo_retry.ActionDomainEvent.class
+    , command = CommandReification.DISABLED
 )
 public class CommandJdo_retry {
 
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_siblingCommands.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_siblingCommands.java
index c01a210..6111389 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_siblingCommands.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_siblingCommands.java
@@ -29,8 +29,12 @@ import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
 
-@Collection(domainEvent = CommandJdo_siblingCommands.CollectionDomainEvent.class)
-@CollectionLayout(defaultView = "table")
+@Collection(
+    domainEvent = CommandJdo_siblingCommands.CollectionDomainEvent.class
+)
+@CollectionLayout(
+    defaultView = "table"
+)
 public class CommandJdo_siblingCommands {
 
     public static class CollectionDomainEvent
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/HasUsername_recentCommandsByUser.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/HasUsername_recentCommandsByUser.java
index a94f9a8..bb6e189 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/HasUsername_recentCommandsByUser.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/HasUsername_recentCommandsByUser.java
@@ -34,13 +34,12 @@ public class HasUsername_recentCommandsByUser {
     public List<CommandJdo> coll() {
         final String username = hasUsername.getUsername();
         return username != null
-                ? commandServiceRepository.findRecentByUser(username)
+                ? commandServiceRepository.findRecentByUsername(username)
                 : Collections.emptyList();
     }
     public boolean hideColl() {
         return hasUsername.getUsername() == null;
     }
 
-    @Inject
-    CommandJdoRepository commandServiceRepository;
+    @Inject CommandJdoRepository commandServiceRepository;
 }
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/T_backgroundCommands.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/T_recent.java
similarity index 66%
rename from extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/T_backgroundCommands.java
rename to extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/T_recent.java
index 8e48b3e..de2af70 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/T_backgroundCommands.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/T_recent.java
@@ -14,30 +14,31 @@ import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 
 @Collection(
-    domainEvent = T_backgroundCommands.CollectionDomainEvent.class
+    domainEvent = T_recent.CollectionDomainEvent.class
 )
 @CollectionLayout(
     defaultView = "table"
 )
-public abstract class T_backgroundCommands<T> {
+public abstract class T_recent<T> {
 
-    public static class CollectionDomainEvent extends IsisModuleExtCommandLogImpl.CollectionDomainEvent<T_backgroundCommands, CommandJdo> { }
+    public static class CollectionDomainEvent
+            extends IsisModuleExtCommandLogImpl.CollectionDomainEvent<T_recent, CommandJdo> { }
 
     private final T domainObject;
-    public T_backgroundCommands(final T domainObject) {
+    public T_recent(final T domainObject) {
         this.domainObject = domainObject;
     }
 
     public List<CommandJdo> coll() {
-        return findRecentBackground();
+        return findRecent();
     }
 
-    private List<CommandJdo> findRecentBackground() {
+    private List<CommandJdo> findRecent() {
         final Bookmark bookmark = bookmarkService.bookmarkFor(domainObject);
         return queryResultsCache.execute(
-                () -> commandJdoRepository.findRecentBackgroundByTarget(bookmark)
-                , T_backgroundCommands.class
-                , "findRecentBackground"
+                () -> commandJdoRepository.findRecentByTarget(bookmark)
+                , T_recent.class
+                , "findRecentByTarget"
                 , domainObject);
     }
 
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/ui/CommandServiceMenu.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/ui/CommandServiceMenu.java
index 685e784..a26937c 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/ui/CommandServiceMenu.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/ui/CommandServiceMenu.java
@@ -33,8 +33,8 @@ import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
     objectType = "isisExtensionsCommandLog.CommandServiceMenu"
 )
 @DomainServiceLayout(
-    named = "Activity"
-    , menuBar = DomainServiceLayout.MenuBar.SECONDARY
+    named = "Activity",
+    menuBar = DomainServiceLayout.MenuBar.SECONDARY
 )
 @Service
 @Named("isisExtensionsCommandLog.CommandServiceMenu")
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/util/BigDecimalUtils.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/util/BigDecimalUtils.java
new file mode 100644
index 0000000..6510573
--- /dev/null
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/util/BigDecimalUtils.java
@@ -0,0 +1,32 @@
+package org.apache.isis.extensions.commandlog.impl.util;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.sql.Timestamp;
+
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+public class BigDecimalUtils {
+
+    /**
+     * @return in seconds, to 3 decimal places.
+     */
+    public static BigDecimal durationBetween(Timestamp startedAt, Timestamp completedAt) {
+        if (completedAt == null) {
+            return null;
+        } else {
+            long millis = completedAt.getTime() - startedAt.getTime();
+            return toSeconds(millis);
+        }
+    }
+
+    private static final BigDecimal DIVISOR = new BigDecimal(1000);
+
+    private static BigDecimal toSeconds(long millis) {
+        return new BigDecimal(millis)
+                .divide(DIVISOR, RoundingMode.HALF_EVEN)
+                .setScale(3, RoundingMode.HALF_EVEN);
+    }
+
+}
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/util/StringUtils.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/util/StringUtils.java
new file mode 100644
index 0000000..04f640f
--- /dev/null
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/util/StringUtils.java
@@ -0,0 +1,17 @@
+package org.apache.isis.extensions.commandlog.impl.util;
+
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+public class StringUtils {
+
+    public static String trimmed(final String str, final int lengthOfField) {
+        if (str == null) {
+            return null;
+        }
+        if (str.length() > lengthOfField) {
+            return str.substring(0, lengthOfField - 3) + "...";
+        }
+        return str;
+    }
+}
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/IsisModuleExtCommandReplayImpl.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/IsisModuleExtCommandReplayImpl.java
index 9c715fe..e04d51a 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/IsisModuleExtCommandReplayImpl.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/IsisModuleExtCommandReplayImpl.java
@@ -9,8 +9,8 @@ import org.apache.isis.extensions.commandreplay.impl.executor.CommandExecutorSer
 import org.apache.isis.extensions.commandreplay.impl.fetch.MasterConfiguration;
 import org.apache.isis.extensions.commandreplay.impl.clock.TickingClockService;
 import org.apache.isis.extensions.commandreplay.impl.analysis.CommandReplayAnalysisService;
-import org.apache.isis.extensions.commandreplay.impl.ui.CommandReplayOnMasterService;
-import org.apache.isis.extensions.commandreplay.impl.ui.CommandReplayOnSlaveService;
+import org.apache.isis.extensions.commandreplay.impl.ui.CommandReplayOnPrimaryService;
+import org.apache.isis.extensions.commandreplay.impl.ui.CommandReplayOnSecondaryService;
 
 @Configuration
 @Import({
@@ -20,8 +20,8 @@ import org.apache.isis.extensions.commandreplay.impl.ui.CommandReplayOnSlaveServ
         // @DomainService's
         CommandExecutorServiceWithTime.class,
         CommandReplayAnalysisService.class,
-        CommandReplayOnMasterService.class,
-        CommandReplayOnSlaveService.class,
+        CommandReplayOnPrimaryService.class,
+        CommandReplayOnSecondaryService.class,
         TickingClockService.class,
 
         // @Service's
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyser.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyser.java
index 5ec040b..5931dde 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyser.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyser.java
@@ -1,12 +1,10 @@
 package org.apache.isis.extensions.commandreplay.impl.analysis;
 
-import org.apache.isis.applib.annotation.Programmatic;
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.schema.cmd.v2.CommandDto;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
 
 public interface CommandReplayAnalyser {
 
-    @Programmatic
-    String analyzeReplay(final Command command, final CommandDto dto);
+    String analyzeReplay(
+            final CommandJdo commandJdo);
 
 }
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserAbstract.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserAbstract.java
index 79d428f..1454d8b 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserAbstract.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserAbstract.java
@@ -5,9 +5,8 @@ import java.util.Map;
 import javax.annotation.PostConstruct;
 
 import org.apache.isis.applib.annotation.Programmatic;
-import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.core.config.metamodel.facets.Util;
-import org.apache.isis.schema.cmd.v2.CommandDto;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
 
 public abstract class CommandReplayAnalyserAbstract implements CommandReplayAnalyser {
 
@@ -33,16 +32,16 @@ public abstract class CommandReplayAnalyserAbstract implements CommandReplayAnal
 
 
     @Programmatic
-    public final String analyzeReplay(final Command command, final CommandDto dto) {
+    public final String analyzeReplay(final CommandJdo commandJdo) {
 
         if(!enabled) {
             return null;
         }
-        return doAnalyzeReplay(command, dto);
+        return doAnalyzeReplay(commandJdo);
 
     }
 
-    protected abstract String doAnalyzeReplay(final Command command, final CommandDto dto);
+    protected abstract String doAnalyzeReplay(final CommandJdo command);
 
     private static String getPropertyElse(final Map<String, String> properties, final String key, final String dflt) {
         final String str = properties.get(key);
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserExceptionStr.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserExceptionStr.java
index 1d98c15..7437631 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserExceptionStr.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserExceptionStr.java
@@ -3,8 +3,10 @@ package org.apache.isis.extensions.commandreplay.impl.analysis;
 import com.google.common.base.Objects;
 
 import org.apache.isis.applib.annotation.DomainService;
-import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.conmap.command.UserDataKeys;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
+import org.apache.isis.core.commons.internal.exceptions._Exceptions;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
 @DomainService()
@@ -18,21 +20,23 @@ public class CommandReplayAnalyserExceptionStr extends CommandReplayAnalyserAbst
         super(ANALYSIS_KEY);
     }
 
-    protected String doAnalyzeReplay(final Command command, final CommandDto dto) {
+    protected String doAnalyzeReplay(final CommandJdo commandJdo) {
 
-        final String masterException =
-                CommandDtoUtils.getUserData(dto, CommandWithDto.USERDATA_KEY_EXCEPTION);
-        if (masterException == null) {
+        final CommandDto dto = commandJdo.getCommandDto();
+
+        final String primaryException =
+                CommandDtoUtils.getUserData(dto, UserDataKeys.EXCEPTION);
+        if (primaryException == null) {
             return null;
         }
 
-        final String replayedException = command.getException();
+        final String replayedException = commandJdo.getException();
 
-        final String masterExceptionTrimmed = trimmed(masterException);
+        final String masterExceptionTrimmed = trimmed(primaryException);
         final String replayedExceptionTrimmed = trimmed(replayedException);
         return Objects.equal(masterExceptionTrimmed, replayedExceptionTrimmed)
                 ? null
-                : String.format("Exceptions differ.  Master was '%s'", masterException);
+                : String.format("Exceptions differ.  Master was '%s'", primaryException);
     }
 
     private String trimmed(final String str) {
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserNumberBackgroundCommands.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserNumberBackgroundCommands.java
deleted file mode 100644
index 565d784..0000000
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserNumberBackgroundCommands.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package org.apache.isis.extensions.commandreplay.impl.analysis;
-
-import java.util.List;
-
-import javax.inject.Inject;
-
-import org.apache.isis.applib.annotation.DomainService;
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.conmap.command.spi.CommandDtoProcessorService;
-import org.apache.isis.applib.util.schema.CommandDtoUtils;
-import org.apache.isis.schema.cmd.v2.CommandDto;
-
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
-
-@DomainService()
-public class CommandReplayAnalyserNumberBackgroundCommands
-        extends CommandReplayAnalyserAbstract
-        implements CommandDtoProcessorService {
-
-    public static final String ANALYSIS_KEY = "isis.services."
-            + CommandReplayAnalyserNumberBackgroundCommands.class.getSimpleName()
-            + ".analysis";
-
-    public static final String USERDATA_KEY_NUMBER_BACKGROUND_COMMANDS = "numberBackgroundCommands";
-
-    public CommandReplayAnalyserNumberBackgroundCommands() {
-        super(ANALYSIS_KEY);
-    }
-
-    /**
-     * Hook for the master, enriches the DTO.
-     */
-    @Override
-    public CommandDto process(final Command command, final CommandDto commandDto) {
-        if(command instanceof CommandJdo) {
-            final CommandJdo commandJdo = (CommandJdo) command;
-
-            final List<CommandJdo> backgroundCommands =
-                    commandJdoRepository.findBackgroundCommandsByParent(commandJdo);
-
-            CommandDtoUtils.setUserData(commandDto,
-                    USERDATA_KEY_NUMBER_BACKGROUND_COMMANDS, ""+backgroundCommands.size());
-        }
-        return commandDto;
-    }
-
-    /**
-     * Hook for the slave.
-     */
-    protected String doAnalyzeReplay(final Command command, final CommandDto dto) {
-        if (!(command instanceof CommandJdo)) {
-            return null;
-        }
-
-        final String masterNumBackgroundCommandsStr =
-                CommandDtoUtils.getUserData(dto, USERDATA_KEY_NUMBER_BACKGROUND_COMMANDS);
-
-        if (masterNumBackgroundCommandsStr == null) {
-            return null;
-        }
-
-        final int masterNumBackgroundCommands;
-        try {
-            masterNumBackgroundCommands = Integer.parseInt(masterNumBackgroundCommandsStr);
-
-        } catch (NumberFormatException ex) {
-            return String.format(
-                    "Unable to check number of background commands; "
-                            + "could not parse '%s' (value of '%s' userdata) in XML",
-                    masterNumBackgroundCommandsStr, USERDATA_KEY_NUMBER_BACKGROUND_COMMANDS);
-        }
-
-        final CommandJdo commandJdo = (CommandJdo) command;
-        final List<CommandJdo> backgroundCommands =
-                commandJdoRepository.findBackgroundCommandsByParent(commandJdo);
-
-        final int slaveNumBackgroundCommands = backgroundCommands.size();
-        if (masterNumBackgroundCommands == slaveNumBackgroundCommands) {
-            return null;
-        }
-
-        return String.format("Number of background commands differs.  Master was %d (slave is %d)",
-                masterNumBackgroundCommands, slaveNumBackgroundCommands);
-    }
-
-    @Inject
-    CommandJdoRepository commandJdoRepository;
-
-}
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserResultStr.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserResultStr.java
index 7aa5177..fd5b4dd 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserResultStr.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserResultStr.java
@@ -1,13 +1,16 @@
 package org.apache.isis.extensions.commandreplay.impl.analysis;
 
+import java.util.Optional;
+
 import com.google.common.base.Objects;
 
 import org.apache.isis.applib.annotation.DomainService;
-import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.conmap.command.UserDataKeys;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
-import org.apache.isis.schema.cmd.v2.CommandDto;
 
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
+import org.apache.isis.schema.cmd.v2.CommandDto;
 
 @DomainService()
 public class CommandReplayAnalyserResultStr extends CommandReplayAnalyserAbstract {
@@ -20,26 +23,23 @@ public class CommandReplayAnalyserResultStr extends CommandReplayAnalyserAbstrac
         super(ANALYSIS_KEY);
     }
 
-    protected String doAnalyzeReplay(final Command command, final CommandDto dto) {
+    protected String doAnalyzeReplay(final CommandJdo commandJdo) {
 
-        if (!(command instanceof CommandJdo)) {
-            return null;
-        }
-
-        final CommandJdo commandJdo = (CommandJdo) command;
+        final CommandDto dto = commandJdo.getCommandDto();
 
         // see if the outcome was the same...
         // ... either the same result when replayed
-        final String masterResultStr =
-                CommandDtoUtils.getUserData(dto, CommandWithDto.USERDATA_KEY_RETURN_VALUE);
-        if (masterResultStr == null) {
-            return null;
-        }
-
-        final String slaveResultStr = commandJdo.getResultStr();
-        return Objects.equal(masterResultStr, slaveResultStr)
+        final String primaryResultStr =
+                CommandDtoUtils.getUserData(dto, UserDataKeys.RESULT);
+
+        final Bookmark secondaryResult = commandJdo.getResult();
+        final String secondaryResultStr =
+                secondaryResult != null ? secondaryResult.toString() : null;
+        return Objects.equal(primaryResultStr, secondaryResultStr)
                 ? null
-                : String.format("Results differ.  Master was '%s'", masterResultStr);
+                : String.format(
+                        "Results differ.  Primary was '%s', secondary is '%s'",
+                        primaryResultStr, secondaryResultStr);
     }
 
 }
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService.java
index ab1936e..dc2e223 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService.java
@@ -5,10 +5,7 @@ import java.util.List;
 import javax.inject.Inject;
 
 import org.apache.isis.applib.annotation.DomainService;
-import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.ReplayState;
-import org.apache.isis.schema.cmd.v2.CommandDto;
 
 import lombok.extern.log4j.Log4j2;
 
@@ -17,27 +14,21 @@ import lombok.extern.log4j.Log4j2;
 public class CommandReplayAnalysisService {
 
     /**
-     * if hit an issue with the command having been replayed, then mark this as in error.
-     * this will effectively block the running of any further commands until the adminstrator fixes the issue.
+     * if hit an issue with the command having been replayed, then mark this
+     * as in error.
+     * This will effectively block the running of any further commands until the adminstrator fixes the issue.
      */
-    @Programmatic
-    public void analyse(final CommandJdo hwmCommand) {
-        final String analysis = analyseReplay(hwmCommand);
-
-        if (analysis == null) {
-            hwmCommand.setReplayState(ReplayState.OK);
-        } else {
-            hwmCommand.setReplayState(ReplayState.FAILED);
-            hwmCommand.setReplayStateFailureReason(trimmed(analysis, 255));
-        }
+    public void analyse(final CommandJdo commandJdo) {
+        final String analysis = analyseReplay(commandJdo);
+
+        commandJdo.saveAnalysis(analysis);
     }
 
     private String analyseReplay(final CommandJdo commandJdo) {
-        final CommandDto dto = commandJdo.getCommandDto();
 
         for (final CommandReplayAnalyser analyser : analysers) {
             try {
-                String reason = analyser.analyzeReplay(commandJdo, dto);
+                String reason = analyser.analyzeReplay(commandJdo);
                 if (reason != null) {
                     return reason;
                 }
@@ -50,14 +41,6 @@ public class CommandReplayAnalysisService {
         return null;
     }
 
-    static String trimmed(final String str, final int lengthOfField) {
-        if(str == null) { return null; }
-        if(str.length() > lengthOfField) {
-            return str.substring(0, lengthOfField - 3) + "...";
-        }
-        return str;
-    }
-
     @Inject List<CommandReplayAnalyser> analysers;
 
 }
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/clock/TickingClockService.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/clock/TickingClockService.java
index 9537ca8..5f60ab0 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/clock/TickingClockService.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/clock/TickingClockService.java
@@ -2,12 +2,11 @@ package org.apache.isis.extensions.commandreplay.impl.clock;
 
 import java.sql.Timestamp;
 import java.util.Optional;
-import java.util.concurrent.Callable;
+import java.util.function.Supplier;
 
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 
-import org.apache.isis.applib.ApplicationException;
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.clock.Clock;
@@ -35,6 +34,8 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 public class TickingClockService {
 
+    @Inject IsisConfiguration isisConfiguration;
+
     @PostConstruct
     public void init() {
         Optional<String> baseUrl = isisConfiguration.getExtensions().getCommandReplay().getMaster().getBaseUrl();
@@ -93,7 +94,7 @@ public class TickingClockService {
      * </p>
      */
     @Programmatic
-    public <T> T at(Timestamp timestamp, Callable<T> callable) {
+    public <T> T at(Timestamp timestamp, Supplier<T> supplier) {
         ensureInitialized();
 
         val tickingFixtureClock = (TickingFixtureClock) TickingFixtureClock.getInstance();
@@ -103,9 +104,7 @@ public class TickingClockService {
 
         try {
             tickingFixtureClock.setTime(timestamp);
-            return callable.call();
-        } catch (Exception e) {
-            throw new ApplicationException(e);
+            return supplier.get();
         } finally {
             final long wallTime1 = System.currentTimeMillis();
             tickingFixtureClock.setTime(previous + wallTime1 - wallTime0);
@@ -119,6 +118,4 @@ public class TickingClockService {
         }
     }
 
-    @Inject IsisConfiguration isisConfiguration;
-
 }
\ No newline at end of file
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/CommandExecutorServiceWithTime.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/CommandExecutorServiceWithTime.java
index 59abc45..2a35c40 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/CommandExecutorServiceWithTime.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/CommandExecutorServiceWithTime.java
@@ -18,6 +18,7 @@ package org.apache.isis.extensions.commandreplay.impl.executor;
 
 import java.sql.Timestamp;
 import java.util.concurrent.Callable;
+import java.util.function.Supplier;
 
 import javax.inject.Named;
 
@@ -56,27 +57,38 @@ public class CommandExecutorServiceWithTime implements CommandExecutorService {
     }
 
     @Override
-    public void executeCommand(final SudoPolicy sudoPolicy, final Command command) {
-        final Runnable executeCommand = () -> delegate.executeCommand(sudoPolicy, command);
-        if(tickingClockService.isInitialized()) {
-            final Timestamp timestamp = command.getTimestamp();
-            tickingClockService.at(timestamp, executeCommand);
-        } else {
-            executeCommand.run();
-        }
+    public Bookmark executeCommand(Command command) {
+        final Supplier<Bookmark> executeCommand = () -> delegate.executeCommand(command);
+        return tickingClockService.isInitialized()
+                ? tickingClockService.at(command.getTimestamp(), executeCommand)
+                : executeCommand.get();
+    }
+
+    @Override
+    public Bookmark executeCommand(final SudoPolicy sudoPolicy, final Command command) {
+        final Supplier<Bookmark> executeCommand = () -> delegate.executeCommand(sudoPolicy, command);
+        return tickingClockService.isInitialized()
+                ? tickingClockService.at(command.getTimestamp(), executeCommand)
+                : executeCommand.get();
     }
 
-    @SneakyThrows
     @Override
     public Bookmark executeCommand(final CommandDto commandDto) {
-        final Callable<Bookmark> executeCommand = () -> delegate.executeCommand(commandDto);
-        if(tickingClockService.isInitialized()) {
-            final Timestamp timestamp =
-                    JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(commandDto.getTimestamp());
-            return tickingClockService.at(timestamp, executeCommand);
-        } else {
-            return executeCommand.call();
-        }
+        final Supplier<Bookmark> executeCommand = () -> delegate.executeCommand(commandDto);
+        return tickingClockService.isInitialized()
+                ? tickingClockService.at(
+                        JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(commandDto.getTimestamp()), executeCommand)
+                : executeCommand.get();
+    }
+
+    @Override
+    public Bookmark executeCommand(
+            final SudoPolicy sudoPolicy, final CommandDto commandDto) {
+        final Supplier<Bookmark> executeCommand = () -> delegate.executeCommand(sudoPolicy, commandDto);
+        return tickingClockService.isInitialized()
+                ? tickingClockService.at(
+                    JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(commandDto.getTimestamp()), executeCommand)
+                : executeCommand.get();
     }
 
 }
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/ReplayableCommandExecution.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/ReplayableCommandExecution.java
index 5da0059..24602e0 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/ReplayableCommandExecution.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/ReplayableCommandExecution.java
@@ -4,9 +4,10 @@ import java.util.List;
 
 import javax.inject.Inject;
 
+import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.command.CommandExecutorService;
 import org.apache.isis.applib.services.xactn.TransactionService;
-import org.apache.isis.core.runtimeservices.background.CommandExecutionAbstract;
+import org.apache.isis.core.runtime.iactn.template.AbstractIsisInteractionTemplate;
 import org.apache.isis.extensions.commandlog.impl.jdo.ReplayState;
 import org.apache.isis.extensions.commandreplay.impl.SlaveStatus;
 import org.apache.isis.extensions.commandreplay.impl.StatusException;
@@ -23,16 +24,17 @@ import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 import lombok.extern.log4j.Log4j2;
 
 @Log4j2
-public class ReplayableCommandExecution
-        extends CommandExecutionAbstract {
+public class ReplayableCommandExecution extends AbstractIsisInteractionTemplate {
 
-    private final MasterConfiguration slaveConfig;
+    private final MasterConfiguration masterConfiguration;
 
-    public ReplayableCommandExecution(final MasterConfiguration slaveConfig) {
-        super(CommandExecutorService.SudoPolicy.SWITCH);
-        this.slaveConfig = slaveConfig;
+    public ReplayableCommandExecution(final MasterConfiguration masterConfiguration) {
+        this.masterConfiguration = masterConfiguration;
     }
 
+    @Inject
+    CommandExecutorService commandExecutorService;
+
     @Override
     protected void doExecute(final Object context) {
         Holder<SlaveStatus> holder = (Holder<SlaveStatus>) context;
@@ -66,41 +68,28 @@ public class ReplayableCommandExecution
 
             }
 
-            log.debug("current hwm transactionId = {} {} {} {}",
+            log.debug("current hwm transactionId = {} {} {}",
                     hwmCommand.getUniqueId(), hwmCommand.getTimestamp(),
-                    hwmCommand.getExecuteIn(), hwmCommand.getMemberIdentifier());
+                    hwmCommand.getLogicalMemberIdentifier());
 
 
             boolean fetchNext;
-            switch (hwmCommand.getExecuteIn()) {
-            case FOREGROUND:
-                fetchNext = true;
-                break;
-            case REPLAYABLE:
-                if(hwmCommand.getReplayState() == null || hwmCommand.getReplayState() == ReplayState.PENDING) {
-
-                    // the HWM has not been replayed.
-                    // this might be because it has been marked for retry by the administrator.
-                    // so, we will just use it directly
-
-                    fetchNext = false;
-                } else {
-                    //
-                    // check that the current HWM was replayed successfully, otherwise break out
-                    //
-                    if(hwmCommand.getReplayState().isFailed()) {
-                        log.info("Command xactnId={} hit replay error", hwmCommand.getUniqueId());
-                        return;
-                    }
-                    fetchNext = true;
+            if(hwmCommand.getReplayState() == null || hwmCommand.getReplayState() == ReplayState.PENDING) {
+
+                // the HWM has not been replayed.
+                // this might be because it has been marked for retry by the administrator.
+                // so, we will just use it directly
+
+                fetchNext = false;
+            } else {
+                //
+                // check that the current HWM was replayed successfully, otherwise break out
+                //
+                if(hwmCommand.getReplayState().isFailed()) {
+                    log.info("Command xactnId={} hit replay error", hwmCommand.getUniqueId());
+                    return;
                 }
-                break;
-            case BACKGROUND:
-            default:
-                log.error(
-                        "HWM command xactnId={} should be either FOREGROUND or REPLAYABLE but is instead {}; aborting",
-                        hwmCommand.getUniqueId(), hwmCommand.getExecuteIn());
-                return;
+                fetchNext = true;
             }
 
             if(fetchNext) {
@@ -117,25 +106,23 @@ public class ReplayableCommandExecution
                         () -> commandJdoRepository.saveForReplay(commandDto));
             }
 
-            log.info("next HWM transactionId = {} {} {} {}", hwmCommand.getUniqueId());
-
+            log.info("next HWM transactionId = {}", hwmCommand.getUniqueId());
 
 
             //
             // run command
             //
-            this.execute(hwmCommand, transactionService);
-
+            executeCommandInTran(hwmCommand);
 
             //
-            // find background commands, and run them
+            // find child commands, and run them
             //
             final CommandJdo parent = hwmCommand;
-            final List<CommandJdo> backgroundCommands =
+            final List<CommandJdo> childCommands =
                     transactionService.executeWithinTransaction(
-                            () -> commandJdoRepository.findBackgroundCommandsByParent(parent));
-            for (final CommandJdo backgroundCommand : backgroundCommands) {
-                execute(backgroundCommand, transactionService);
+                        () -> commandJdoRepository.findByParent(parent));
+            for (final CommandJdo childCommand : childCommands) {
+                executeCommandInTran(childCommand);
             }
 
 
@@ -147,6 +134,11 @@ public class ReplayableCommandExecution
         }
     }
 
+    private void executeCommandInTran(final CommandJdo command) {
+        transactionService.executeWithinTransaction(
+                () -> commandExecutorService.executeCommand(CommandExecutorService.SudoPolicy.SWITCH, command.getCommandDto()));
+    }
+
     private boolean isRunning() {
 
         // if no controller implementation provided, then just continue
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/fetch/CommandFetcher.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/fetch/CommandFetcher.java
index def3c0b..0f034e6 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/fetch/CommandFetcher.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/fetch/CommandFetcher.java
@@ -12,6 +12,7 @@ import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.jaxb.JaxbService;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
 import org.apache.isis.extensions.commandreplay.impl.SlaveStatus;
 import org.apache.isis.extensions.commandreplay.impl.StatusException;
 import org.apache.isis.extensions.jaxrsclient.applib.client.JaxRsClient;
@@ -38,9 +39,8 @@ public class CommandFetcher {
      * @return
      * @throws StatusException
      */
-    @Programmatic
     public CommandDto fetchCommand(
-            final Command previousHwm)
+            final CommandJdo previousHwm)
             throws StatusException {
 
         log.debug("finding command on master ...");
@@ -60,8 +60,9 @@ public class CommandFetcher {
     /**
      * @return - the commands, or <tt>null</tt> if none were found
      * @throws StatusException
+     * @param previousHwm
      */
-    private CommandsDto fetchCommands(final Command previousHwm) throws StatusException {
+    private CommandsDto fetchCommands(final CommandJdo previousHwm) throws StatusException {
         final UUID transactionId = previousHwm != null ? previousHwm.getUniqueId() : null;
 
         log.debug("finding commands on master ...");
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_download.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_download.java
index 6faef66..766e6ac 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_download.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_download.java
@@ -11,12 +11,12 @@ import org.apache.isis.applib.value.Clob;
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
 import org.apache.isis.extensions.commandreplay.impl.IsisModuleExtCommandReplayImpl;
 
-import org.apache.isis.extensions.commandreplay.impl.ui.CommandReplayOnMasterService;
+import org.apache.isis.extensions.commandreplay.impl.ui.CommandReplayOnPrimaryService;
 
 @Action(
         semantics = SemanticsOf.NON_IDEMPOTENT,
-        domainEvent = CommandJdo_download.ActionDomainEvent.class,
-        commandPersistence = CommandPersistence.NOT_PERSISTED
+        domainEvent = CommandJdo_download.ActionDomainEvent.class
+
 )
 @ActionLayout(
         cssClassFa = "fa-download",
@@ -37,7 +37,7 @@ public class CommandJdo_download {
     public Clob act(
             @ParameterLayout(named="Filename prefix")
             final String fileNamePrefix) {
-        return commandReplayOnMasterService.downloadCommandById(commandJdo.getUniqueId(), fileNamePrefix);
+        return commandReplayOnPrimaryService.downloadCommandById(commandJdo.getUniqueId(), fileNamePrefix);
     }
     public String default0Act() {
         return "command";
@@ -45,5 +45,5 @@ public class CommandJdo_download {
 
 
     @Inject
-    CommandReplayOnMasterService commandReplayOnMasterService;
+    CommandReplayOnPrimaryService commandReplayOnPrimaryService;
 }
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_exclude.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_exclude.java
index 071f818..05ef148 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_exclude.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_exclude.java
@@ -12,8 +12,8 @@ import lombok.extern.log4j.Log4j2;
 
 @Action(
         semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE,
-        domainEvent = CommandJdo_exclude.ActionDomainEvent.class,
-        commandPersistence = CommandPersistence.NOT_PERSISTED
+        domainEvent = CommandJdo_exclude.ActionDomainEvent.class
+
 )
 @Log4j2
 public class CommandJdo_exclude {
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayNext.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayNext.java
index 93f9a7a..5c85d9f 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayNext.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayNext.java
@@ -19,10 +19,11 @@ import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.extensions.commandreplay.impl.fetch.CommandFetcher;
 import org.apache.isis.extensions.commandreplay.impl.analysis.CommandReplayAnalysisService;
 
+import lombok.val;
+
 @Action(
         semantics = SemanticsOf.NON_IDEMPOTENT,
-        domainEvent = CommandJdo_replayNext.ActionDomainEvent.class,
-        commandPersistence = CommandPersistence.NOT_PERSISTED
+        domainEvent = CommandJdo_replayNext.ActionDomainEvent.class
 )
 public class CommandJdo_replayNext {
 
@@ -66,12 +67,12 @@ public class CommandJdo_replayNext {
     private void execute(final CommandJdo hwmCommand) {
 
         // execute the hwm command
-        commandExecutorService.executeCommand(CommandExecutorService.SudoPolicy.SWITCH, hwmCommand);
+        commandExecutorService.executeCommand(CommandExecutorService.SudoPolicy.SWITCH, hwmCommand.getCommandDto());
 
-        // find background commands, and run them
-        final List<CommandJdo> backgroundCommands = commandJdoRepository.findBackgroundCommandsByParent(hwmCommand);
-        for (final CommandJdo backgroundCommand : backgroundCommands) {
-            commandExecutorService.executeCommand(CommandExecutorService.SudoPolicy.SWITCH, backgroundCommand);
+        // find child commands, and run them
+        val childCommands = commandJdoRepository.findByParent(hwmCommand);
+        for (final CommandJdo childCommand : childCommands) {
+            commandExecutorService.executeCommand(CommandExecutorService.SudoPolicy.SWITCH, childCommand.getCommandDto());
         }
     }
 
@@ -81,18 +82,13 @@ public class CommandJdo_replayNext {
         if(commandJdo != replayHwm) {
             return "This action can only be performed against the 'HWM' command on the slave";
         }
-        if(commandJdo.getExecuteIn().isReplayable() && commandJdo.getReplayState() != null && commandJdo.getReplayState().isFailed()) {
+        if(commandJdo.getReplayState() != null && commandJdo.getReplayState().isFailed()) {
             return "Replayable command is in error.  Exclude the command to continue.";
         }
         if(!commandJdo.isComplete()) {
             return "Replayable command is not complete";
         }
 
-        if(commandJdo.getExecuteIn().isBackground()) {
-            // this shouldn't happen; findReplayHwm should never return a background command
-            return "Background commands cannot be replayed";
-        }
-
         return null;
     }
 
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayQueue.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayQueue.java
index 924c861..2bc91e6 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayQueue.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayQueue.java
@@ -32,7 +32,7 @@ public class CommandJdo_replayQueue {
 
     @MemberOrder(sequence = "100.100")
     public List<CommandJdo> coll() {
-        return commandJdoRepository.findReplayedOnSlave();
+        return commandJdoRepository.findReplayedOnSecondary();
     }
 
     public boolean hideColl() {
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/quartz/RunBackgroundCommandsWithReplicationAndReplayJob.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/quartz/RunBackgroundCommandsWithReplicationAndReplayJob.java
index 034a3db..7a955b3 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/quartz/RunBackgroundCommandsWithReplicationAndReplayJob.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/quartz/RunBackgroundCommandsWithReplicationAndReplayJob.java
@@ -35,31 +35,21 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 public class RunBackgroundCommandsWithReplicationAndReplayJob implements Job {
 
-    private static final Logger LOG = LoggerFactory.getLogger(RunBackgroundCommandsWithReplicationAndReplayJob.class);
-
     AuthenticationSession authSession;
-    MasterConfiguration slaveConfig;
+    MasterConfiguration masterConfiguration;
 
     public void execute(final JobExecutionContext quartzContext) {
 
         // figure out if this instance is configured to run as master or slave
         authSession = new SimpleSessionFromQuartz(quartzContext);
         final IsisConfiguration isisConfiguration = lookupIsisConfiguration(authSession);
-        slaveConfig = new MasterConfiguration(isisConfiguration);
+        masterConfiguration = new MasterConfiguration(isisConfiguration);
 
-        if(!slaveConfig.isConfigured()) {
-            runBackgroundCommandsOnMaster();
-        } else {
+        if(masterConfiguration.isConfigured()) {
             runBackgroundCommandsOnSlave(quartzContext);
         }
     }
 
-    private void runBackgroundCommandsOnMaster() {
-        // same as the original RunBackgroundCommandsJob
-        val executionService = new BackgroundCommandExecutionFromBackgroundCommandServiceJdo();
-        executionService.execute(authSession, null);
-    }
-
     private void runBackgroundCommandsOnSlave(final JobExecutionContext quartzContext) {
         final SlaveStatus slaveStatus =
                 getSlaveStatus(quartzContext, SlaveStatus.TICKING_CLOCK_STATUS_UNKNOWN);
@@ -68,19 +58,15 @@ public class RunBackgroundCommandsWithReplicationAndReplayJob implements Job {
 
             case TICKING_CLOCK_STATUS_UNKNOWN:
             case TICKING_CLOCK_NOT_YET_INITIALIZED:
-                final boolean initialized = lookupTickingClockServiceStatus(authSession);
-                if(initialized) {
-                    setSlaveStatus(quartzContext, SlaveStatus.OK);
-                    // go round the loop
-                    runBackgroundCommandsOnMaster();
-                } else {
-                    setSlaveStatus(quartzContext, SlaveStatus.TICKING_CLOCK_NOT_YET_INITIALIZED);
-                }
+                setSlaveStatus(quartzContext,
+                        lookupTickingClockServiceStatus(authSession)
+                            ? SlaveStatus.OK
+                            : SlaveStatus.TICKING_CLOCK_NOT_YET_INITIALIZED);
                 return;
 
             case OK:
                 Holder<SlaveStatus> holder = new Holder<>();
-                new ReplayableCommandExecution(slaveConfig).execute(authSession, holder);
+                new ReplayableCommandExecution(masterConfiguration).execute(authSession, holder);
                 final SlaveStatus newStatus = holder.getObject();
                 if(newStatus != null) {
                     setSlaveStatus(quartzContext, newStatus);
@@ -91,7 +77,7 @@ public class RunBackgroundCommandsWithReplicationAndReplayJob implements Job {
             case REST_CALL_FAILING:
             case FAILED_TO_UNMARSHALL_RESPONSE:
             case UNKNOWN_STATE:
-                LOG.warn("skipped - configured as slave, however: {}" ,slaveStatus);
+                log.warn("skipped - configured as slave, however: {}" ,slaveStatus);
                 return;
             default:
                 throw new IllegalStateException("Unrecognised status: " + slaveStatus);
@@ -181,6 +167,5 @@ public class RunBackgroundCommandsWithReplicationAndReplayJob implements Job {
         setString(context, KEY_SLAVE_STATUS, mode.name());
     }
 
-
 }
 
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnMasterService.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnPrimaryService.java
similarity index 74%
rename from extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnMasterService.java
rename to extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnPrimaryService.java
index c3bb759..7087893 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnMasterService.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnPrimaryService.java
@@ -15,7 +15,6 @@ import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.NatureOfService;
 import org.apache.isis.applib.annotation.ParameterLayout;
 import org.apache.isis.applib.annotation.SemanticsOf;
-import org.apache.isis.applib.services.conmap.command.ContentMappingServiceForCommandDto;
 import org.apache.isis.applib.services.conmap.command.ContentMappingServiceForCommandsDto;
 import org.apache.isis.applib.services.jaxb.JaxbService;
 import org.apache.isis.applib.services.message.MessageService;
@@ -31,20 +30,20 @@ import lombok.extern.log4j.Log4j2;
 
 @DomainService(
         nature = NatureOfService.VIEW,
-        objectType = "isisextcommandreplay.CommandReplayOnMasterService"
+        objectType = "isisExtensionsCommandReplay.CommandReplayOnPrimaryService"
 )
 @DomainServiceLayout(
         named = "Activity",
         menuBar = DomainServiceLayout.MenuBar.SECONDARY
 )
 @Log4j2
-public class CommandReplayOnMasterService {
+public class CommandReplayOnPrimaryService {
 
     public static abstract class ActionDomainEvent
-            extends IsisModuleExtCommandReplayImpl.ActionDomainEvent<CommandReplayOnMasterService> { }
+            extends IsisModuleExtCommandReplayImpl.ActionDomainEvent<CommandReplayOnPrimaryService> { }
 
 
-    public static class FindCommandsOnMasterSinceDomainEvent extends ActionDomainEvent { }
+    public static class FindCommandsOnPrimarySinceDomainEvent extends ActionDomainEvent { }
     public static class NotFoundException extends ApplicationException {
         private static final long serialVersionUID = 1L;
         @Getter
@@ -65,7 +64,7 @@ public class CommandReplayOnMasterService {
      * @return
      * @throws NotFoundException - if the command with specified transaction cannot be found.
      */
-    @Action(domainEvent = FindCommandsOnMasterSinceDomainEvent.class, semantics = SemanticsOf.SAFE)
+    @Action(domainEvent = FindCommandsOnPrimarySinceDomainEvent.class, semantics = SemanticsOf.SAFE)
     @ActionLayout(cssClassFa = "fa-files-o")
     @MemberOrder(sequence="40")
     public List<CommandJdo> findCommandsOnMasterSince(
@@ -76,7 +75,7 @@ public class CommandReplayOnMasterService {
             @ParameterLayout(named="Batch size")
             final Integer batchSize)
             throws NotFoundException {
-        final List<CommandJdo> commands = commandServiceRepository.findForegroundSince(transactionId, batchSize);
+        final List<CommandJdo> commands = commandServiceRepository.findSince(transactionId, batchSize);
         if(commands == null) {
             throw new NotFoundException(transactionId);
         }
@@ -93,7 +92,7 @@ public class CommandReplayOnMasterService {
      * These actions should be called with HTTP Accept Header set to:
      * <code>application/xml;profile="urn:org.restfulobjects:repr-types/action-result";x-ro-domain-type="org.apache.isis.schema.cmd.v1.CommandsDto"</code>
      *
-     * @param transactionId - to search from.  This transactionId will <i>not</i> be included in the response.
+     * @param uniqueId - to search from.  This transactionId will <i>not</i> be included in the response.
      * @param batchSize - the maximum number of commands to return.  If not specified, all found will be returned.
      *
      * @return
@@ -104,14 +103,11 @@ public class CommandReplayOnMasterService {
     @MemberOrder(sequence="50")
     public Clob downloadCommandsOnMasterSince(
             @Nullable
-            @ParameterLayout(named="Transaction Id")
-            final UUID transactionId,
+            final UUID uniqueId,
             @Nullable
-            @ParameterLayout(named="Batch size")
             final Integer batchSize,
-            @ParameterLayout(named="Filename prefix")
-            final String fileNamePrefix) {
-        final List<CommandJdo> commands = commandServiceRepository.findForegroundSince(transactionId, batchSize);
+            final String filenamePrefix) {
+        final List<CommandJdo> commands = commandServiceRepository.findSince(uniqueId, batchSize);
         if(commands == null) {
             messageService.informUser("No commands found");
         }
@@ -120,16 +116,11 @@ public class CommandReplayOnMasterService {
                 contentMappingServiceForCommandsDto.map(commands);
 
         final String fileName = String.format(
-                "%s_%s.xml", fileNamePrefix, elseDefault(transactionId));
+                "%s_%s.xml", filenamePrefix, elseDefault(uniqueId));
 
         final String xml = jaxbService.toXml(commandsDto);
         return new Clob(fileName, "application/xml", xml);
     }
-
-    private String elseDefault(final UUID transactionId) {
-        return transactionId != null ? transactionId.toString() : "00000000-0000-0000-0000-000000000000";
-    }
-
     public Integer default1DownloadCommandsOnMasterSince() {
         return 25;
     }
@@ -139,33 +130,30 @@ public class CommandReplayOnMasterService {
 
 
 
-    public static class DownloadCommandOnMasterDomainEvent extends ActionDomainEvent { }
+    public static class DownloadCommandFromPrimaryDomainEvent extends ActionDomainEvent { }
     /**
      * This action should be called with HTTP Accept Header set to:
      * <code>application/xml;profile="urn:org.restfulobjects:repr-types/action-result";x-ro-domain-type="org.apache.isis.schema.cmd.v1.CommandDto"</code>
      *
-     * @param transactionId - to download.
+     * @param uniqueId - to download.
      *
      * @return
      * @throws NotFoundException - if the command with specified transaction cannot be found.
      */
-    @Action(domainEvent = DownloadCommandOnMasterDomainEvent.class, semantics = SemanticsOf.SAFE)
+    @Action(domainEvent = DownloadCommandFromPrimaryDomainEvent.class, semantics = SemanticsOf.SAFE)
     @ActionLayout(cssClassFa = "fa-download")
     @MemberOrder(sequence="50")
     public Clob downloadCommandById(
-            @ParameterLayout(named="Transaction Id")
-            final UUID transactionId,
-            @ParameterLayout(named="Filename prefix")
-            final String fileNamePrefix) {
+            final UUID uniqueId,
+            final String filenamePrefix) {
 
-        return commandServiceRepository.findByUniqueId(transactionId)
+        return commandServiceRepository.findByUniqueId(uniqueId)
                 .map(commandJdo -> {
 
-                    final CommandDto commandDto =
-                            contentMappingServiceForCommandDto.map(commandJdo);
+                    final CommandDto commandDto = commandJdo.getCommandDto();
 
                     final String fileName = String.format(
-                            "%s_%s.xml", fileNamePrefix, elseDefault(transactionId));
+                            "%s_%s.xml", filenamePrefix, elseDefault(uniqueId));
 
                     final String xml = jaxbService.toXml(commandDto);
                     return new Clob(fileName, "application/xml", xml);
@@ -180,11 +168,13 @@ public class CommandReplayOnMasterService {
     }
 
 
-    @Inject
-    CommandJdoRepository commandServiceRepository;
+    private static String elseDefault(final UUID uuid) {
+        return uuid != null ? uuid.toString() : "00000000-0000-0000-0000-000000000000";
+    }
+
+    @Inject CommandJdoRepository commandServiceRepository;
     @Inject JaxbService jaxbService;
     @Inject MessageService messageService;
     @Inject ContentMappingServiceForCommandsDto contentMappingServiceForCommandsDto;
-    @Inject ContentMappingServiceForCommandDto contentMappingServiceForCommandDto;
 }
 
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnSlaveService.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnSecondaryService.java
similarity index 76%
rename from extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnSlaveService.java
rename to extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnSecondaryService.java
index cbd037c..5f059d2 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnSlaveService.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnSecondaryService.java
@@ -24,38 +24,36 @@ import lombok.extern.log4j.Log4j2;
 
 @DomainService(
         nature = NatureOfService.VIEW,
-        objectType = "isiscommand.CommandReplayOnSlaveService"
+        objectType = "isisExtensionsCommandReplay.CommandReplayOnSecondaryService"
 )
 @DomainServiceLayout(
         named = "Activity",
         menuBar = DomainServiceLayout.MenuBar.SECONDARY
 )
 @Log4j2
-public class CommandReplayOnSlaveService {
+public class CommandReplayOnSecondaryService {
 
     public static abstract class ActionDomainEvent
-            extends IsisModuleExtCommandReplayImpl.ActionDomainEvent<CommandReplayOnMasterService> { }
+            extends IsisModuleExtCommandReplayImpl.ActionDomainEvent<CommandReplayOnSecondaryService> { }
 
-
-    public static class FindReplayHwmOnSlaveDomainEvent extends ActionDomainEvent { }
-    @Action(domainEvent = FindReplayHwmOnSlaveDomainEvent.class, semantics = SemanticsOf.SAFE)
+    public static class FindReplayHwmOnSecondaryDomainEvent extends ActionDomainEvent { }
+    @Action(domainEvent = FindReplayHwmOnSecondaryDomainEvent.class, semantics = SemanticsOf.SAFE)
     @ActionLayout(cssClassFa = "fa-bath")
     @MemberOrder(sequence="60.1")
-    public CommandJdo findReplayHwmOnSlave() {
+    public CommandJdo findReplayHwmOnSecondary() {
         return commandJdoRepository.findReplayHwm();
     }
 
 
 
-    public static class UploadCommandsToSlaveDomainEvent extends ActionDomainEvent { }
+    public static class UploadCommandsToSecondaryDomainEvent extends ActionDomainEvent { }
     @Action(
-        command = CommandReification.DISABLED,
-        domainEvent = UploadCommandsToSlaveDomainEvent.class,
+        domainEvent = UploadCommandsToSecondaryDomainEvent.class,
         semantics = SemanticsOf.NON_IDEMPOTENT
     )
     @ActionLayout(cssClassFa = "fa-upload")
     @MemberOrder(sequence="60.2")
-    public void uploadCommandsToSlave(final Clob commandsDtoAsXml) {
+    public void uploadCommandsToSecondary(final Clob commandsDtoAsXml) {
         final CharSequence chars = commandsDtoAsXml.getChars();
         List<CommandDto> commandDtoList;
 
@@ -74,9 +72,7 @@ public class CommandReplayOnSlaveService {
     }
 
 
-
-    @Inject
-    CommandJdoRepository commandJdoRepository;
+    @Inject CommandJdoRepository commandJdoRepository;
     @Inject JaxbService jaxbService;
 
 }
diff --git a/extensions/core/quartz/impl/src/main/java/org/apache/isis/extensions/quartz/jobs/RunBackgroundCommandsJob.java b/extensions/core/quartz/impl/src/main/java/org/apache/isis/extensions/quartz/jobs/DemoJob.java
similarity index 76%
rename from extensions/core/quartz/impl/src/main/java/org/apache/isis/extensions/quartz/jobs/RunBackgroundCommandsJob.java
rename to extensions/core/quartz/impl/src/main/java/org/apache/isis/extensions/quartz/jobs/DemoJob.java
index 75712e4..ba51ff8 100644
--- a/extensions/core/quartz/impl/src/main/java/org/apache/isis/extensions/quartz/jobs/RunBackgroundCommandsJob.java
+++ b/extensions/core/quartz/impl/src/main/java/org/apache/isis/extensions/quartz/jobs/DemoJob.java
@@ -14,14 +14,13 @@ import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 @Log4j2
-public class RunBackgroundCommandsJob implements Job {
+public class DemoJob implements Job {
 
     public void execute(final JobExecutionContext context) {
 
         final AuthenticationSession authSession = newAuthSession(context);
 
-        log.debug("Running background commands");
-        backgroundCommandExecutionFromBackgroundCommandServiceJdo.execute(authSession, null);
+        log.debug("Running job");
     }
 
     protected AuthenticationSession newAuthSession(JobExecutionContext context) {
@@ -32,7 +31,6 @@ public class RunBackgroundCommandsJob implements Job {
         return new SimpleSession(user, roles);
     }
 
-    @Inject BackgroundCommandExecutionFromBackgroundCommandServiceJdo backgroundCommandExecutionFromBackgroundCommandServiceJdo;
     @Inject IsisConfiguration isisConfiguration;
 
 }
diff --git a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/DomainObjectContainer.java b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/DomainObjectContainer.java
index 5edf7da..58cd1c8 100644
--- a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/DomainObjectContainer.java
+++ b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/DomainObjectContainer.java
@@ -51,6 +51,9 @@ import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.legacy.applib.filter.Filter;
 import org.apache.isis.persistence.jdo.applib.services.IsisJdoSupport;
 
+/**
+ * @deprecated
+ */
 @Service
 @Named("isisLegacyApplib.domainObjectContainer")
 @Order(OrderPrecedence.MIDPOINT)
diff --git a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/background/BackgroundCommandService2.java b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/background/BackgroundCommandService2.java
deleted file mode 100644
index eb67f3d..0000000
--- a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/background/BackgroundCommandService2.java
+++ /dev/null
@@ -1,30 +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.legacy.applib.services.background;
-
-import org.apache.isis.applib.services.background.BackgroundCommandService;
-
-/**
- * Persists a {@link org.apache.isis.schema.cmd.v1.CommandDto memento-ized} command such that it can be
- * executed asynchronously, for example through a Quartz scheduler.
- * @deprecated use BackgroundCommandService instead
- */
-@Deprecated
-public interface BackgroundCommandService2 extends BackgroundCommandService {
-
-    
-}
diff --git a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/background/BackgroundService.java b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/background/BackgroundService.java
deleted file mode 100644
index 0d69872..0000000
--- a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/background/BackgroundService.java
+++ /dev/null
@@ -1,60 +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.legacy.applib.services.background;
-
-import org.apache.isis.applib.services.wrapper.WrapperFactory;
-
-/**
- * Submit actions to be invoked in the background.
- *
- * <p>
- * Example usage:
- * <pre>
- * public void submitInvoices() {
- *     for(Customer customer: customerRepository.findCustomersToInvoice()) {
- *         backgroundService.execute(customer).submitInvoice();
- *     }
- * }
- *
- * &#64;javax.inject.Inject
- * private BackgroundService backgroundService;
- * </pre>
- * 
- * @deprecated replaced by the {@link WrapperFactory#async(Object)}
- */
-public interface BackgroundService {
-
-    /**
-     * Returns a proxy around the object (entity or view model) which is then used to obtain the
-     * signature of the action to be invoked in the background.
-     *
-     * <p>
-     *     To obtain a proxy for a mixin, use {@link #executeMixin(Class, Object)}.
-     * </p>
-     */
-    <T> T execute(final T object);
-
-    /**
-     * Returns a proxy around the mixin object which is then used to obtain the
-     * signature of the action to be invoked in the background.
-     */
-    <T> T executeMixin(Class<T> mixinClass, Object mixedIn);
-
-
-}
diff --git a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/background/BackgroundService2.java b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/background/BackgroundService2.java
deleted file mode 100644
index c1f7d6a..0000000
--- a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/background/BackgroundService2.java
+++ /dev/null
@@ -1,28 +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.legacy.applib.services.background;
-
-/**
- * Submit actions to be invoked in the background.
- * @deprecated use BackgroundService instead
- * 
- */
-@Deprecated
-public interface BackgroundService2 extends BackgroundService {
-   
-
-}
diff --git a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/eventbus/ActionDomainEvent.java b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/eventbus/ActionDomainEvent.java
index bb9e9fb..3714f9e 100644
--- a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/eventbus/ActionDomainEvent.java
+++ b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/eventbus/ActionDomainEvent.java
@@ -28,6 +28,9 @@ import org.apache.isis.applib.services.command.CommandContext;
 import org.apache.isis.applib.util.ObjectContracts;
 import org.apache.isis.applib.util.ToString;
 
+/**
+ * @deprecated
+ */
 @Deprecated
 public abstract class ActionDomainEvent<S> extends AbstractDomainEvent<S> {
 
diff --git a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/eventbus/CollectionDomainEvent.java b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/eventbus/CollectionDomainEvent.java
index 472ed5f..07d5799 100644
--- a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/eventbus/CollectionDomainEvent.java
+++ b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/eventbus/CollectionDomainEvent.java
@@ -22,6 +22,9 @@ import org.apache.isis.applib.events.domain.AbstractDomainEvent;
 import org.apache.isis.applib.util.ObjectContracts;
 import org.apache.isis.applib.util.ToString;
 
+/**
+ * @deprecated
+ */
 @Deprecated
 public abstract class CollectionDomainEvent<S, T> extends AbstractDomainEvent<S> {
 
diff --git a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/eventbus/PropertyDomainEvent.java b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/eventbus/PropertyDomainEvent.java
index 3498b0e..185bbb6 100644
--- a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/eventbus/PropertyDomainEvent.java
+++ b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/services/eventbus/PropertyDomainEvent.java
@@ -22,6 +22,10 @@ import org.apache.isis.applib.events.domain.AbstractDomainEvent;
 import org.apache.isis.applib.util.ObjectContracts;
 import org.apache.isis.applib.util.ToString;
 
+/**
+ * @deprecated
+ */
+@Deprecated
 public abstract class PropertyDomainEvent<S,T> extends AbstractDomainEvent<S> {
 
     // -- Default class
diff --git a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Color.java b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Color.java
index 87c33ac..102e8f6 100644
--- a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Color.java
+++ b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Color.java
@@ -28,7 +28,10 @@ import org.apache.isis.applib.annotation.Value;
  * <p>
  * Where there is no basic colors (RGB all equal 0) then you get black; where
  * each color is at maximum (RGB all equal 255) you get white.
+ *
+ * @deprecated
  */
+@Deprecated
 @Value(semanticsProviderName = "org.apache.isis.core.metamodel.facets.value.color.ColorValueSemanticsProvider")
 public class Color extends Magnitude<Color> {
 
diff --git a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Magnitude.java b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Magnitude.java
index 5f28862..cac9b3a 100644
--- a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Magnitude.java
+++ b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Magnitude.java
@@ -21,6 +21,10 @@ package org.apache.isis.legacy.applib.value;
 
 import java.io.Serializable;
 
+/**
+ * @deprecated
+ */
+@Deprecated
 public abstract class Magnitude<T extends Magnitude<T>> implements Serializable {
     private static final long serialVersionUID = 1L;
 
diff --git a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Money.java b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Money.java
index 82bc539..648510b 100644
--- a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Money.java
+++ b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Money.java
@@ -23,7 +23,11 @@ import java.math.BigDecimal;
 
 import org.apache.isis.applib.annotation.Value;
 
+/**
+ * @deprecated
+ */
 @Value(semanticsProviderName = "org.apache.isis.core.metamodel.facets.value.money.MoneyValueSemanticsProvider")
+@Deprecated
 public class Money extends Magnitude<Money> {
 
     private static final long serialVersionUID = 1L;
diff --git a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Percentage.java b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Percentage.java
index b99e6fb..c23a457 100644
--- a/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Percentage.java
+++ b/legacy/extensions/core/applib/src/main/java/org/apache/isis/legacy/applib/value/Percentage.java
@@ -21,7 +21,11 @@ package org.apache.isis.legacy.applib.value;
 
 import org.apache.isis.applib.annotation.Value;
 
+/**
+ * @deprecated
+ */
 @Value(semanticsProviderName = "org.apache.isis.core.metamodel.facets.value.percentage.PercentageValueSemanticsProvider")
+@Deprecated
 public class Percentage extends Magnitude<Percentage> {
 
     private static final long serialVersionUID = 1L;
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/service/JdoPersistenceLifecycleService.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/service/JdoPersistenceLifecycleService.java
index 901e7d9..4d1124f 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/service/JdoPersistenceLifecycleService.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/service/JdoPersistenceLifecycleService.java
@@ -52,9 +52,9 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 public class JdoPersistenceLifecycleService {
 
-    @Inject private MetaModelContext metaModelContext;
-    @Inject private PersistenceSessionFactory persistenceSessionFactory;
-    @Inject private IsisBeanTypeRegistryHolder isisBeanTypeRegistryHolder;
+    @Inject MetaModelContext metaModelContext;
+    @Inject PersistenceSessionFactory persistenceSessionFactory;
+    @Inject IsisBeanTypeRegistryHolder isisBeanTypeRegistryHolder;
 
     @PostConstruct
     public void postConstr() {
@@ -89,6 +89,7 @@ public class JdoPersistenceLifecycleService {
     public void onSessionLifecycleEvent(IsisInteractionLifecycleEvent event) {
 
         val eventType = event.getEventType();
+        val isisInteraction = event.getIsisInteraction();
 
         if(log.isDebugEnabled()) {
             log.debug("received session event {}", eventType);
@@ -96,13 +97,13 @@ public class JdoPersistenceLifecycleService {
 
         switch (eventType) {
         case HAS_STARTED:
-            openSession(event.getIsisInteraction());
+            openSession(isisInteraction);
             break;
         case IS_ENDING:
-            closeSession(event.getIsisInteraction());
+            closeSession(isisInteraction);
             break;
         case FLUSH_REQUEST:
-            flushSession(event.getIsisInteraction());
+            flushSession(isisInteraction);
             break;
 
         default:
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisBookmarkConverter.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisBookmarkConverter.java
index 838a998..6064f2f 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisBookmarkConverter.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisBookmarkConverter.java
@@ -38,7 +38,7 @@ public class IsisBookmarkConverter implements TypeConverter<Bookmark, String>{
     @Override
     public Bookmark toMemberType(final String datastoreValue) {
         return datastoreValue != null
-                ? Bookmark.parse(datastoreValue)
+                ? Bookmark.parse(datastoreValue).orElse(null)
                         : null;
     }
 
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/IsisPersistenceSessionJdoBase.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/IsisPersistenceSessionJdoBase.java
index d7486e9..49a6fc7 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/IsisPersistenceSessionJdoBase.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/IsisPersistenceSessionJdoBase.java
@@ -27,7 +27,7 @@ import javax.jdo.PersistenceManagerFactory;
 
 import org.apache.isis.applib.services.clock.ClockService;
 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.factory.FactoryService;
 import org.apache.isis.applib.services.iactn.InteractionContext;
 import org.apache.isis.applib.services.inject.ServiceInjector;
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/PersistenceSession5.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/PersistenceSession5.java
index 10c8dca..06dc3cc 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/PersistenceSession5.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/PersistenceSession5.java
@@ -76,6 +76,7 @@ import org.apache.isis.core.metamodel.facets.object.callbacks.UpdatingLifecycleE
 import org.apache.isis.core.metamodel.services.container.query.QueryCardinality;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.runtime.persistence.transaction.IsisTransactionObject;
 import org.apache.isis.persistence.jdo.applib.exceptions.NotPersistableException;
 import org.apache.isis.persistence.jdo.applib.exceptions.UnsupportedFindException;
 import org.apache.isis.persistence.jdo.applib.fixturestate.FixturesInstalledStateHolder;
@@ -193,8 +194,8 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
      * Closes the subcomponents.
      *
      * <p>
-     * Automatically {@link IsisTransactionManagerJdo#commitTransaction() ends
-     * (commits)} the current (Isis) {@link IsisTransactionJdo}. This in turn commits the underlying
+     * Automatically {@link IsisTransactionManagerJdo#commitTransaction(IsisTransactionObject)
+     * ends (commits)} the current (Isis) {@link IsisTransactionJdo}. This in turn commits the underlying
      * JDO transaction.
      *
      * <p>
@@ -210,29 +211,6 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
 
         completeCommandFromInteractionAndClearDomainEvents();
 
-        //TODO[2125] should no longer be required		
-        //		try {
-        //			val currentTransaction = transactionManager.getCurrentTransaction();
-        //			transactionManager.flushTransaction(currentTransaction);
-        //			if (currentTransaction != null && !currentTransaction.getState().isComplete()) {
-        //				if(currentTransaction.getState().canCommit()) {
-        //					transactionManager.commitTransaction(currentTransaction);
-        //				} else if(currentTransaction.getState().canAbort()) {
-        //					transactionManager.abortTransaction(currentTransaction);
-        //				}
-        //			}
-        //		} catch(final Throwable ex) {
-        //			// ignore
-        //			log.error("close: failed to end transaction; continuing to avoid memory leakage");
-        //		}
-
-        // tell the proxy of all request-scoped services to invoke @PreDestroy
-        // (if any) on all underlying services stored on their thread-locals...
-        //preDestroyOnRequestScopedServices();
-
-        // ... and then remove those underlying services from the thread-local
-        //endRequestOnRequestScopeServices();
-
         persistenceManager.removeInstanceLifecycleListener(storeLifecycleListener);
         
         try {
@@ -248,50 +226,30 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
         this.state = State.CLOSED;
     }
 
-//    private void endRequestOnRequestScopeServices() {
-//        serviceRegistry.select(RequestScopedService.class)
-//        .forEach(RequestScopedService::__isis_endRequest);
-//    }
-//
-//    private void preDestroyOnRequestScopedServices() {
-//        serviceRegistry.select(RequestScopedService.class)
-//        .forEach(RequestScopedService::__isis_preDestroy);
-//    }
-
     private void completeCommandFromInteractionAndClearDomainEvents() {
 
-        final Command command = commandContextProvider.get().getCommand();
-        final Interaction interaction = interactionContextProvider.get().getInteraction();
-
+        val command = commandContextProvider.get().getCommand();
+        val interaction = interactionContextProvider.get().getInteraction();
 
         if(command.getStartedAt() != null && command.getCompletedAt() == null) {
             // the guard is in case we're here as the result of a redirect following a previous exception;just ignore.
 
-            final Timestamp completedAt;
-            final Interaction.Execution<?, ?> priorExecution = interaction.getPriorExecution();
-            if (priorExecution != null) {
-                // copy over from the most recent (which will be the top-level) interaction
-                completedAt = priorExecution.getCompletedAt();
-            } else {
-                // this could arise as the result of calling SessionManagementService#nextSession within an action
-                // the best we can do is to use the current time
+            val priorInteractionExecution = interaction.getPriorExecution();
+            final Timestamp completedAt =
+                    priorInteractionExecution != null
+                    ?
+                        // copy over from the most recent (which will be the top-level) interaction
+                        priorInteractionExecution.getCompletedAt()
+                    :
+                        // this could arise as the result of calling SessionManagementService#nextSession within an action
+                        // the best we can do is to use the current time
 
-                // REVIEW: as for the interaction object, it is left somewhat high-n-dry.
-                completedAt = clockService.nowAsJavaSqlTimestamp();
-            }
+                        // REVIEW: as for the interaction object, it is left somewhat high-n-dry.
+                         clockService.nowAsJavaSqlTimestamp();
 
             command.internal().setCompletedAt(completedAt);
         }
 
-        // ensureCommandsPersistedIfDirtyXactn
-
-        // ensure that any changed objects means that the command should be persisted
-        if(command.getMemberIdentifier() != null) {
-            if(metricsServiceProvider.get().numberObjectsDirtied() > 0) {
-                command.internal().setPersistHint(true);
-            }
-        }
-
         commandService.complete(command);
 
         interaction.clear();
diff --git a/testing/integtestsupport/applib/src/main/java/org/apache/isis/testing/integtestsupport/applib/IsisIntegrationTestAbstract.java b/testing/integtestsupport/applib/src/main/java/org/apache/isis/testing/integtestsupport/applib/IsisIntegrationTestAbstract.java
index bf15bdf..33c8535 100644
--- a/testing/integtestsupport/applib/src/main/java/org/apache/isis/testing/integtestsupport/applib/IsisIntegrationTestAbstract.java
+++ b/testing/integtestsupport/applib/src/main/java/org/apache/isis/testing/integtestsupport/applib/IsisIntegrationTestAbstract.java
@@ -54,15 +54,7 @@ import lombok.val;
 public abstract class IsisIntegrationTestAbstract {
 
     /**
-     * If included as a service, then ensures that any {@link Command}s created (eg as a result of
-     * {@link Action#command()} set to {@link CommandReification#ENABLED}) will be appear to be created as
-     * user initiatied.
-     *
-     * <p>
-     *     Most integration tests won't be concerned with such details, but tests that verify the interaction with the
-     *     {@link org.apache.isis.applib.services.command.spi.CommandService} implementations may require this
-     *     behaviour.
-     * </p>
+     * Hook to interact with {@link Command}s (currently unused).
      */
     @Service
     @Order(OrderPrecedence.MIDPOINT)
@@ -73,22 +65,8 @@ public abstract class IsisIntegrationTestAbstract {
 
         @EventListener
         public void on(final TransactionAfterBeginEvent event) {
-            setupCommand();
         }
-        
-        private void setupCommand() {
-            val commandContext = commandContextProvider.get();
-            val command = commandContext.getCommand();
-            if(command == null) {
-                return;
-            }
-            final Command.Executor executor = command.getExecutor();
-            if(executor != Command.Executor.OTHER) {
-                return;
-            }
-            command.internal().setExecutor(Command.Executor.USER);
-        }
-        
+
     }
 
     /**
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
index ceac803..950c600 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
@@ -206,11 +206,15 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
         return domainResourceHelper.objectRepresentation();
     }
 
+    @DELETE
+    @Path("/{domainType}/{instanceId}")
     @Override
     public Response deleteMethodNotSupported(@PathParam("domainType") String domainType, @PathParam("instanceId") String instanceId) {
         throw RestfulObjectsApplicationException.createWithMessage(HttpStatusCode.METHOD_NOT_ALLOWED, "Deleting objects is not supported.");
     }
 
+    @POST
+    @Path("/{domainType}/{instanceId}")
     @Override
     public Response postMethodNotAllowed(@PathParam("domainType") String domainType, @PathParam("instanceId") String instanceId) {
         throw RestfulObjectsApplicationException.createWithMessage(HttpStatusCode.METHOD_NOT_ALLOWED, "Posting to object resource is not allowed.");
@@ -448,8 +452,6 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
         val resourceContext = createResourceContext(
                 ResourceDescriptor.generic(Where.OBJECT_FORMS, RepresentationService.Intent.NOT_APPLICABLE));
 
-        setCommandExecutor(Command.Executor.USER);
-
         val objectAdapter = getObjectAdapterElseThrowNotFound(domainType, instanceId);
         
         PropertyInteraction.start(objectAdapter, propertyId, resourceContext.getWhere())
@@ -480,8 +482,6 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
         val resourceContext = createResourceContext(
                 ResourceDescriptor.generic(Where.OBJECT_FORMS, RepresentationService.Intent.NOT_APPLICABLE));
 
-        setCommandExecutor(Command.Executor.USER);
-        
         val objectAdapter = getObjectAdapterElseThrowNotFound(domainType, instanceId);
         
         PropertyInteraction.start(objectAdapter, propertyId, resourceContext.getWhere())
@@ -494,6 +494,8 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
                 .propertyDetails(propertyId, ManagedMember.RepresentationMode.WRITE);
     }
 
+    @POST
+    @Path("/{domainType}/{instanceId}/properties/{propertyId}")
     @Override
     public Response postPropertyNotAllowed(@PathParam("domainType") String domainType, @PathParam("instanceId") String instanceId, @PathParam("propertyId") String propertyId) {
         throw RestfulObjectsApplicationException.createWithMessage(HttpStatusCode.METHOD_NOT_ALLOWED, "Posting to a property resource is not allowed.");
@@ -661,16 +663,22 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
         return domainResourceHelper.actionPrompt(actionId);
     }
 
+    @DELETE
+    @Path("/{domainType}/{instanceId}/actions/{actionId}")
     @Override
     public Response deleteActionPromptNotAllowed(@PathParam("domainType") String domainType, @PathParam("instanceId") String instanceId, @PathParam("actionId") String actionId) {
         throw RestfulObjectsApplicationException.createWithMessage(HttpStatusCode.METHOD_NOT_ALLOWED, "Deleting action prompt resource is not allowed.");
     }
 
+    @POST
+    @Path("/{domainType}/{instanceId}/actions/{actionId}")
     @Override
     public Response postActionPromptNotAllowed(@PathParam("domainType") String domainType, @PathParam("instanceId") String instanceId, @PathParam("actionId") String actionId) {
         throw RestfulObjectsApplicationException.createWithMessage(HttpStatusCode.METHOD_NOT_ALLOWED, "Posting to an action prompt resource is not allowed.");
     }
 
+    @PUT
+    @Path("/{domainType}/{instanceId}/actions/{actionId}")
     @Override
     public Response putActionPromptNotAllowed(@PathParam("domainType") String domainType, @PathParam("instanceId") String instanceId, @PathParam("actionId") String actionId) {
         throw RestfulObjectsApplicationException.createWithMessage(HttpStatusCode.METHOD_NOT_ALLOWED, "Putting to an action prompt resource is not allowed.");
@@ -700,8 +708,6 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
                 ResourceDescriptor.of(RepresentationType.ACTION_RESULT, Where.STANDALONE_TABLES, RepresentationService.Intent.NOT_APPLICABLE),
                 urlUnencodedQueryString);
 
-        setCommandExecutor(Command.Executor.USER);
-
         final JsonRepresentation arguments = resourceContext.getQueryStringAsJsonRepr();
 
         val objectAdapter = getObjectAdapterElseThrowNotFound(domainType, instanceId);
@@ -728,8 +734,6 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
                 ResourceDescriptor.of(RepresentationType.ACTION_RESULT, Where.STANDALONE_TABLES, RepresentationService.Intent.NOT_APPLICABLE),
                 body);
 
-        setCommandExecutor(Command.Executor.USER);
-
         final JsonRepresentation arguments = resourceContext.getQueryStringAsJsonRepr();
 
         val objectAdapter = getObjectAdapterElseThrowNotFound(domainType, instanceId);
@@ -756,8 +760,6 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
                 ResourceDescriptor.of(RepresentationType.ACTION_RESULT, Where.STANDALONE_TABLES, RepresentationService.Intent.NOT_APPLICABLE),
                 body);
 
-        setCommandExecutor(Command.Executor.USER);
-
         final JsonRepresentation arguments = resourceContext.getQueryStringAsJsonRepr();
 
         val objectAdapter = getObjectAdapterElseThrowNotFound(domainType, instanceId);
@@ -766,6 +768,8 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
         return domainResourceHelper.invokeAction(actionId, arguments);
     }
 
+    @DELETE
+    @Path("/{domainType}/{instanceId}/actions/{actionId}/invoke")
     @Override
     public Response deleteInvokeActionNotAllowed(@PathParam("domainType") String domainType, @PathParam("instanceId") String instanceId, @PathParam("actionId") String actionId) {
         throw RestfulObjectsApplicationException.createWithMessage(RestfulResponse.HttpStatusCode.METHOD_NOT_ALLOWED, "Deleting an action invocation resource is not allowed.");
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainServiceResourceServerside.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainServiceResourceServerside.java
index 33010bf..943a05a 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainServiceResourceServerside.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainServiceResourceServerside.java
@@ -24,6 +24,7 @@ import java.util.stream.Stream;
 
 import javax.inject.Inject;
 import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
@@ -145,16 +146,22 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
         return Responses.ofOk(renderer, Caching.ONE_DAY).build();
     }
 
+    @DELETE
+    @Path("/{serviceId}")
     @Override
     public Response deleteServiceNotAllowed(@PathParam("serviceId") String serviceId) {
         throw RestfulObjectsApplicationException.createWithMessage(RestfulResponse.HttpStatusCode.METHOD_NOT_ALLOWED, "Deleting a service resource is not allowed.");
     }
 
+    @PUT
+    @Path("/{serviceId}")
     @Override
     public Response putServiceNotAllowed(@PathParam("serviceId") String serviceId) {
         throw RestfulObjectsApplicationException.createWithMessage(RestfulResponse.HttpStatusCode.METHOD_NOT_ALLOWED, "Putting to a service resource is not allowed.");
     }
 
+    @POST
+    @Path("/{serviceId}")
     @Override
     public Response postServiceNotAllowed(@PathParam("serviceId") String serviceId) {
         throw RestfulObjectsApplicationException.createWithMessage(RestfulResponse.HttpStatusCode.METHOD_NOT_ALLOWED, "Posting to a service resource is not allowed.");
@@ -183,16 +190,22 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
         return domainResourceHelper.actionPrompt(actionId);
     }
 
+    @DELETE
+    @Path("/{serviceId}/actions/{actionId}")
     @Override
     public Response deleteActionPromptNotAllowed(@PathParam("serviceId") String serviceId, @PathParam("actionId") String actionId) {
         throw RestfulObjectsApplicationException.createWithMessage(RestfulResponse.HttpStatusCode.METHOD_NOT_ALLOWED, "Deleting action prompt resource is not allowed.");
     }
 
+    @PUT
+    @Path("/{serviceId}/actions/{actionId}")
     @Override
     public Response putActionPromptNotAllowed(@PathParam("serviceId") String serviceId, @PathParam("actionId") String actionId) {
         throw RestfulObjectsApplicationException.createWithMessage(RestfulResponse.HttpStatusCode.METHOD_NOT_ALLOWED, "Putting to an action prompt resource is not allowed.");
     }
 
+    @POST
+    @Path("/{serviceId}/actions/{actionId}")
     @Override
     public Response postActionPromptNotAllowed(@PathParam("serviceId") String serviceId, @PathParam("actionId") String actionId) {
         throw RestfulObjectsApplicationException.createWithMessage(RestfulResponse.HttpStatusCode.METHOD_NOT_ALLOWED, "Posting to an action prompt resource is not allowed.");
@@ -220,8 +233,6 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
                 ResourceDescriptor.of(RepresentationType.ACTION_RESULT, Where.STANDALONE_TABLES, RepresentationService.Intent.NOT_APPLICABLE),
                 urlUnencodedQueryString);
 
-        setCommandExecutor(Command.Executor.USER);
-
         final JsonRepresentation arguments = resourceContext.getQueryStringAsJsonRepr();
 
         val serviceAdapter = getServiceAdapter(serviceId);
@@ -248,8 +259,6 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
                 ResourceDescriptor.of(RepresentationType.ACTION_RESULT, Where.STANDALONE_TABLES, RepresentationService.Intent.NOT_APPLICABLE),
                 body);
 
-        setCommandExecutor(Command.Executor.USER);
-
         final JsonRepresentation arguments = resourceContext.getQueryStringAsJsonRepr();
 
         val serviceAdapter = getServiceAdapter(serviceId);
@@ -272,8 +281,6 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
                 ResourceDescriptor.of(RepresentationType.ACTION_RESULT, Where.STANDALONE_TABLES, RepresentationService.Intent.NOT_APPLICABLE),
                 body);
 
-        setCommandExecutor(Command.Executor.USER);
-
         final JsonRepresentation arguments = resourceContext.getQueryStringAsJsonRepr();
 
         val serviceAdapter = getServiceAdapter(serviceId);
@@ -282,6 +289,8 @@ public class DomainServiceResourceServerside extends ResourceAbstract implements
         return domainResourceHelper.invokeAction(actionId, arguments);
     }
 
+    @DELETE
+    @Path("/{serviceId}/actions/{actionId}/invoke")
     @Override
     public Response deleteInvokeActionNotAllowed(@PathParam("serviceId") String serviceId, @PathParam("actionId") String actionId) {
         throw RestfulObjectsApplicationException.createWithMessage(RestfulResponse.HttpStatusCode.METHOD_NOT_ALLOWED, "Deleting an action invocation resource is not allowed.");
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/ResourceAbstract.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/ResourceAbstract.java
index ee3d49f..21d2d2d 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/ResourceAbstract.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/ResourceAbstract.java
@@ -33,8 +33,6 @@ import javax.ws.rs.core.UriInfo;
 import javax.ws.rs.ext.Providers;
 
 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.internal.codec._UrlDecoderUtil;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
@@ -125,13 +123,6 @@ public abstract class ResourceAbstract {
                 resourceDescriptor, "/restful", /*urlUnencodedQueryString*/ null, requestParams);
     }
 
-    // --
-    
-    protected void setCommandExecutor(Command.Executor executor) {
-        metaModelContext.getServiceRegistry()
-        .lookupServiceElseFail(CommandContext.class).getCommand().internal().setExecutor(executor);
-    }
-
     // -- ISIS INTEGRATION
 
     protected ManagedObject getObjectAdapterElseThrowNotFound(String domainType, final String instanceIdEncoded) {
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/app/logout/LogoutHandlerWkt.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/app/logout/LogoutHandlerWkt.java
index bbf2fe9..3ede5ba 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/app/logout/LogoutHandlerWkt.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/app/logout/LogoutHandlerWkt.java
@@ -32,7 +32,7 @@ import lombok.val;
 @Service
 public class LogoutHandlerWkt implements LogoutHandler {
 
-    @Inject private IsisInteractionTracker isisInteractionTracker;
+    @Inject IsisInteractionTracker isisInteractionTracker;
 
     @Override
     public void logout() {
@@ -45,9 +45,7 @@ public class LogoutHandlerWkt implements LogoutHandler {
         if(isisInteractionTracker.isInInteraction()) {
             isisInteractionTracker.currentInteraction()
             .ifPresent(interaction->
-                interaction.setOnClose(()->{
-                    currentWktSession.invalidateNow();
-                }));
+                interaction.setOnClose(currentWktSession::invalidateNow));
             
         } else {
             currentWktSession.invalidateNow();
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
index 329546c..97d41e9 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
@@ -131,7 +131,6 @@ implements CollectionCountProvider {
     }
 
 
-
     private void addTitleColumn(
             final List<IColumn<ManagedObject, String>> columns,
             final ObjectMemento parentAdapterMementoIfAny,
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupPanelFactories.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupPanelFactories.java
index 34ca6e6..c96c9a3 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupPanelFactories.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/markup/MarkupPanelFactories.java
@@ -149,10 +149,7 @@ public class MarkupPanelFactories {
 
         @Override
         protected MarkupComponentFactory getMarkupComponentFactory() {
-            return (id, model) -> {
-                val markupComponent = new MarkupComponent(id, model);
-                return markupComponent;    
-            };
+            return MarkupComponent::new;
         }
     }
 
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/mixins/Object_clearHints.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/mixins/Object_clearHints.java
index ff363ae..2f82040 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/mixins/Object_clearHints.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/mixins/Object_clearHints.java
@@ -22,10 +22,9 @@ 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.CommandReification;
 import org.apache.isis.applib.annotation.Contributed;
 import org.apache.isis.applib.annotation.MemberOrder;
-import org.apache.isis.applib.annotation.Mixin;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.services.hint.HintStore;
@@ -34,28 +33,24 @@ import org.apache.isis.viewer.wicket.viewer.services.HintStoreUsingWicketSession
 import lombok.RequiredArgsConstructor;
 import lombok.val;
 
-@Mixin(method="act")
+@Action(
+        domainEvent = Object_clearHints.ActionDomainEvent.class,
+        semantics = SemanticsOf.IDEMPOTENT,
+        command = CommandReification.DISABLED
+)
+@ActionLayout(
+        contributed = Contributed.AS_ACTION,
+        cssClassFa = "far fa-circle",
+        position = ActionLayout.Position.PANEL_DROPDOWN
+)
 @RequiredArgsConstructor
 public class Object_clearHints {
 
-    @Inject private HintStore hintStore;
-    @Inject private BookmarkService bookmarkService;
-    
-    private final Object holder;
-
-    public static class ActionDomainEvent 
+    public static class ActionDomainEvent
     extends org.apache.isis.applib.events.domain.ActionDomainEvent<Object> {}
 
-    @Action(
-            domainEvent = ActionDomainEvent.class,
-            semantics = SemanticsOf.IDEMPOTENT,
-            commandPersistence = CommandPersistence.NOT_PERSISTED
-            )
-    @ActionLayout(
-            contributed = Contributed.AS_ACTION,
-            cssClassFa = "far fa-circle",
-            position = ActionLayout.Position.PANEL_DROPDOWN
-            )
+    private final Object holder;
+
     @MemberOrder(name = "datanucleusIdLong", sequence = "400.1")
     public Object act() {
         if (getHintStoreUsingWicketSession() != null) {
@@ -78,4 +73,7 @@ public class Object_clearHints {
                         : null;
     }
 
+    @Inject HintStore hintStore;
+    @Inject BookmarkService bookmarkService;
+
 }


[isis] 01/03: ISIS-2222: reworking command, lots of stuff here...

Posted by da...@apache.org.
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 bfffbd4fa4f72e734fdb399cfe4b9f479d4c959f
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Sep 4 10:58:07 2020 +0100

     ISIS-2222: reworking command, lots of stuff here...
---
 .../applib-ant/examples/annotation/Action.java     |   1 -
 .../applib-ant/examples/annotation/Property.java   |   1 -
 .../modules/applib-ant/pages/Action/command.adoc   |   1 +
 .../mixins/layout/Object_rebuildMetamodel.java     |   1 -
 .../examples/services/command/Command.java         |   3 -
 .../examples/services/command/CommandDefault.java  |   2 -
 .../ContentMappingServiceForCommandDto.java        |   1 -
 .../org/apache/isis/applib/annotation/Action.java  |  32 -
 .../isis/applib/annotation/CommandExecuteIn.java   |  83 ---
 .../isis/applib/annotation/CommandPersistence.java |  52 --
 .../isis/applib/annotation/CommandReification.java |  56 --
 .../apache/isis/applib/annotation/Property.java    |  34 +-
 .../mixins/layout/Object_rebuildMetamodel.java     |  22 +-
 .../isis/applib/services/DomainChangeAbstract.java | 296 ---------
 .../isis/applib/services/DomainChangeRecord.java   | 155 +++++
 .../DomainChangeRecord_openTargetObject.java       |  61 ++
 .../background/BackgroundCommandService.java       |  59 --
 .../isis/applib/services/bookmark/Bookmark.java    |   1 +
 .../isis/applib/services/command/Command.java      | 412 +++++--------
 .../applib/services/command/CommandContext.java    |   7 -
 .../applib/services/command/CommandDefault.java    | 186 ------
 .../CommandDtoProcessorForActionAbstract.java      |   4 +-
 .../CommandDtoProcessorForPropertyAbstract.java    |   4 +-
 .../services/command/CommandExecutorService.java   |   4 +-
 .../services/command/spi/CommandService.java       |   2 +-
 .../ContentMappingServiceForCommandDto.java        |  30 +-
 .../java/org/apache/isis/applib/util/ToString.java |  17 +-
 .../isis/applib/util/schema/CommandDtoUtils.java   |   4 +
 .../apache/isis/core/config/IsisConfiguration.java |   5 +-
 .../command/CommandFacetForActionAnnotation.java   |   5 +-
 ...ommandFacetForActionAnnotationAsConfigured.java |   2 -
 .../command/CommandFacetFromConfiguration.java     |   4 +-
 .../actions/action/invocation/CommandUtil.java     |  26 +
 .../facets/actions/command/CommandFacet.java       |  16 -
 .../actions/command/CommandFacetAbstract.java      |  38 --
 .../command/CommandFacetForPropertyAnnotation.java |   5 +-
 ...mandFacetForPropertyAnnotationAsConfigured.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 +-
 .../valuetypes/ValueTypeProviderForBuiltin.java    |   7 +-
 .../ActionAnnotationFacetFactoryTest_Command.java  |   3 -
 .../background/BackgroundCommandExecution.java     |   1 -
 .../background/CommandExecutionAbstract.java       |   1 -
 .../command/CommandDtoServiceInternalDefault.java  |  22 +-
 .../command/CommandExecutorServiceDefault.java     |  42 +-
 .../command/CommandServiceDefault.java             |   3 +-
 examples/demo/domain/pom.xml                       |   8 +-
 .../src/main/java/demoapp/dom/DemoModule.java      |   5 +-
 .../ActionCommandDisabledMetaAnnotation.java       |   3 -
 .../Action/command/ActionCommandJdo.java           |   6 -
 .../Action/command/ActionCommandJdo.layout.xml     |   3 +-
 .../ActionCommandJdo_backgroundCommands.java       |  39 --
 .../ActionCommandJdo_clearBackgroundCommands.java  |  38 --
 .../ActionCommandJdo_clearForegroundCommands.java  |  38 --
 ...ommands.java => ActionCommandJdo_commands.java} |  14 +-
 ...ActionCommandJdo_executeBackgroundCommands.java |  39 --
 .../spiimpl/CommandServiceSpiForActions.java       |  95 ---
 .../impl/IsisModuleExtCommandLogImpl.java          |  10 +-
 .../commandlog/impl/api/UserDataKeys.java          |  21 +-
 ...ndExecutionFromBackgroundCommandServiceJdo.java |  29 -
 .../background/BackgroundCommandServiceJdo.java    |  92 ---
 .../BackgroundCommandServiceJdoRepository.java     |  48 --
 .../extensions/commandlog/impl/jdo/CommandJdo.java | 672 +++++++--------------
 ...doRepository.java => CommandJdoRepository.java} | 121 ++--
 .../impl/jdo/CommandJdo_childCommands.java         |  23 +-
 .../impl/jdo/CommandJdo_openResultObject.java      |  18 +
 .../commandlog/impl/jdo/CommandJdo_retry.java      |  87 +--
 .../impl/jdo/CommandJdo_siblingCommands.java       |  31 +-
 .../commandlog/impl/jdo/CommandServiceJdo.java     |  99 ---
 .../commandlog/impl/jdo/ReplayState.java           |  34 ++
 .../impl/mixins/HasUniqueId_command.java           |   7 +-
 .../mixins/HasUsername_recentCommandsByUser.java   |   5 +-
 .../impl/mixins/Object_recentCommands.java         |   4 +-
 .../impl/mixins/T_backgroundCommands.java          |   7 +-
 .../commandlog/impl/ui/CommandServiceMenu.java     |   7 +-
 .../CommandReplayAnalyserExceptionStr.java         |   1 -
 ...mandReplayAnalyserNumberBackgroundCommands.java |   9 +-
 .../analysis/CommandReplayAnalyserResultStr.java   |   1 -
 .../analysis/CommandReplayAnalysisService.java     |   3 +-
 .../executor/CommandExecutorServiceWithTime.java   |   9 +-
 .../impl/executor/ReplayableCommandExecution.java  |  19 +-
 .../impl/mixins/CommandJdo_download.java           |   3 +-
 .../impl/mixins/CommandJdo_exclude.java            |   1 -
 .../impl/mixins/CommandJdo_replayNext.java         |  13 +-
 .../impl/mixins/CommandJdo_replayQueue.java        |   6 +-
 ...kgroundCommandsWithReplicationAndReplayJob.java |   1 -
 .../impl/ui/CommandReplayOnMasterService.java      |   7 +-
 .../impl/ui/CommandReplayOnSlaveService.java       |   9 +-
 .../quartz/jobs/RunBackgroundCommandsJob.java      |   4 -
 .../IsisBookmarkConverter.java}                    |  16 +-
 .../IsisLocalResourcePathConverter.java            |   2 +-
 .../{ => applib}/IsisMarkupConverter.java          |   2 +-
 .../{ => applib}/IsisPasswordConverter.java        |   2 +-
 .../v2/IsisChangesDtoConverter.java}               |  15 +-
 .../v2/IsisCommandDtoConverter.java}               |  17 +-
 .../v2/IsisInteractionDtoConverter.java}           |  14 +-
 .../v2/IsisOidDtoConverter.java}                   |  21 +-
 .../{ => applib}/ByteArrayBlobRdbmsMapping.java    |   2 +-
 .../valuetypes/{ => applib}/IsisBlobMapping.java   |   2 +-
 .../valuetypes/{ => applib}/IsisClobMapping.java   |   2 +-
 .../persistence/PersistenceSession5.java           |   3 +-
 .../datanucleus-5/src/main/resources/plugin.xml    |  96 ++-
 .../components/scalars/bookmark/BookmarkPanel.java |  29 +-
 .../scalars/bookmark/BookmarkPanelFactory.java     |  27 +-
 .../ui/components/scalars/oiddto/OidDtoPanel.java  |  27 +-
 .../scalars/oiddto/OidDtoPanelFactory.java         |  25 +-
 .../wicket/ui/panels/FormExecutorDefault.java      |  12 +-
 .../ComponentFactoryRegistrarDefault.java          |   7 +
 111 files changed, 1184 insertions(+), 2702 deletions(-)

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..26d5ca3 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,7 +27,6 @@ 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.conmap.command.ContentMappingServiceForCommandDto;
 import org.apache.isis.applib.services.conmap.command.ContentMappingServiceForCommandsDto;
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..cc2d0a9 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,7 +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;
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..075c67a 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.
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..82b7cc4 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;
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..afa0be6 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
@@ -22,11 +22,8 @@ import java.sql.Timestamp;
 
 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.bookmark.Bookmark;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.services.iactn.Interaction;
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
index 069acd4..e24b08b 100644
--- 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
@@ -21,8 +21,6 @@ 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;
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..ef6925f 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
@@ -34,7 +34,6 @@ import org.apache.isis.applib.annotation.OrderPrecedence;
 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;
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..8d4a22f 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,7 +27,6 @@ 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.conmap.command.ContentMappingServiceForCommandDto;
 import org.apache.isis.applib.services.conmap.command.ContentMappingServiceForCommandsDto;
@@ -91,37 +90,6 @@ public @interface Action {
 
     // end::refguide[]
     /**
-     * Whether the action invocation should be reified into a {@link org.apache.isis.applib.services.command.Command} object.
-     */
-    // tag::refguide[]
-    CommandReification command()                                    // <.>
-            default CommandReification.NOT_SPECIFIED;
-
-    // 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/CommandReification.java b/api/applib/src/main/java/org/apache/isis/applib/annotation/CommandReification.java
deleted file mode 100644
index a2b8b68..0000000
--- a/api/applib/src/main/java/org/apache/isis/applib/annotation/CommandReification.java
+++ /dev/null
@@ -1,56 +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;
-
-/**
- * The available policies as to whether action invocations are reified into commands.
- */
-// tag::refguide[]
-public enum CommandReification {
-    // end::refguide[]
-    /**
-     * Whether the action should be handled as a command as per the default command configured in <tt>applicationp.properties</tt>.
-     *
-     * <p>
-     *     If no command policy is configured, then the action is <i>not</i> treated as a command.
-     * </p>
-     */
-    // tag::refguide[]
-    AS_CONFIGURED,
-    // end::refguide[]
-    /**
-     * Handle the action as a command, irrespective of any configuration settings.
-     */
-    // tag::refguide[]
-    ENABLED,
-    // end::refguide[]
-    /**
-     * Do not handle the action as a command, irrespective of any configuration settings.
-     */
-    // tag::refguide[]
-    DISABLED,
-    // end::refguide[]
-    /**
-     * Ignore the value provided by this annotation (meaning that the framework will keep searching, in meta
-     * annotations or superclasses/interfaces).
-     */
-    // tag::refguide[]
-    NOT_SPECIFIED
-}
-// 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..1488a33 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,7 +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;
@@ -52,37 +51,6 @@ public @interface Property {
 
     // end::refguide[]
     /**
-     * Whether the property edit should be reified into a {@link org.apache.isis.applib.services.command.Command} object.
-     */
-    // tag::refguide[]
-    CommandReification command()                                // <.>
-            default CommandReification.NOT_SPECIFIED;
-
-    // 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>
@@ -210,7 +178,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/DomainChangeAbstract.java b/api/applib/src/main/java/org/apache/isis/applib/services/DomainChangeAbstract.java
deleted file mode 100644
index 4a19bd6..0000000
--- a/api/applib/src/main/java/org/apache/isis/applib/services/DomainChangeAbstract.java
+++ /dev/null
@@ -1,296 +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;
-
-import java.sql.Timestamp;
-import java.util.UUID;
-
-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.extern.log4j.Log4j2;
-
-
-/**
- * An abstraction of some sort of recorded change to a domain object: commands, audit entries or published events.
- */
-@Log4j2
-public abstract class DomainChangeAbstract
-        implements HasUniqueId, HasUsername {
-
-    public static enum ChangeType {
-        COMMAND,
-        AUDIT_ENTRY,
-        PUBLISHED_INTERACTION;
-        @Override
-        public String toString() {
-            return name().replace("_", " ");
-        }
-    }
-    public DomainChangeAbstract(final ChangeType changeType) {
-        this.type = changeType;
-    }
-
-    /**
-     * 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")
-    @Getter
-    private final ChangeType type;
-
-
-
-    /**
-     * The user that caused the change.
-     *
-     * <p>
-     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
-     * subclasses override with the &quot;real&quot; implementation.
-     */
-    @Property
-    @MemberOrder(name="Identifiers", sequence = "10")
-    public String getUser() {
-        return null;
-    }
-
-
-
-    /**
-     * The time that the change occurred.
-     *
-     * <p>
-     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
-     * subclasses override with the &quot;real&quot; implementation.
-     */
-    @Property
-    @MemberOrder(name="Identifiers", sequence = "20")
-    public Timestamp getTimestamp() {
-        return null;
-    }
-
-
-    /**
-     * The unique identifier (a GUID) of the transaction in which this change occurred.
-     *
-     * <p>
-     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
-     * subclasses override with the &quot;real&quot; implementation.
-     */
-    @Property
-    @MemberOrder(name="Identifiers",sequence = "50")
-    public UUID getTransactionId() {
-        return null;
-    }
-
-
-    /**
-     * The class of the domain object being changed.
-     *
-     * <p>
-     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
-     * subclasses override with the &quot;real&quot; implementation.
-     */
-    @Property
-    @PropertyLayout(named="Class")
-    @MemberOrder(name="Target", sequence = "10")
-    public String getTargetClass() {
-        return null;
-    }
-
-
-
-    @Programmatic
-    public Bookmark getTarget() {
-        final String str = getTargetStr();
-        return Bookmark.parse(str).orElse(null);
-    }
-
-    @Programmatic
-    public void setTarget(Bookmark target) {
-        final String targetStr = target != null ? target.toString() : null;
-        setTargetStr(targetStr);
-    }
-
-
-    /**
-     * 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>
-     *
-     * <p>
-     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
-     * subclasses override with the &quot;real&quot; implementation.
-     * </p>
-     *
-     * <p>
-     *     NB: commands and published events applied only to actions, hence the name of this field.  In a future release
-     *     the name of this field may change to &quot;TargetMember&quot;.  Note that the {@link PropertyLayout} already uses
-     *     &quot;Member&quot; this as a name hint.
-     * </p>
-     *
-     */
-    @Property(optionality = Optionality.OPTIONAL)
-    @PropertyLayout(
-            named="Member",
-            hidden = Where.ALL_EXCEPT_STANDALONE_TABLES
-    )
-    @MemberOrder(name="Target", sequence = "20")
-    @Getter
-    private String targetAction;
-
-
-
-    /**
-     * The (string representation of the) {@link Bookmark} identifying the domain object that has changed.
-     *
-     * <p>
-     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
-     * subclasses override with the &quot;real&quot; implementation.
-     */
-    @Property
-    @PropertyLayout(named="Object")
-    @MemberOrder(name="Target", sequence="30")
-    public String getTargetStr() {
-        return null;
-    }
-
-    /**
-     * For {@link #setTarget(Bookmark)} to delegate to.
-     */
-    public abstract void setTargetStr(final String targetStr);
-
-
-
-    @Action(semantics = SemanticsOf.SAFE)
-    @ActionLayout(named = "Open")
-    @MemberOrder(name="TargetStr", sequence="1")
-    public Object openTargetObject() {
-        try {
-            return bookmarkService != null
-                    ? bookmarkService.lookup(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 getTarget() == null;
-    }
-
-    public String disableOpenTargetObject() {
-        final Object targetObject = getTarget();
-        if (targetObject == null) {
-            return null;
-        }
-        final BeanSort sortOfObject = metaModelService.sortOf(getTarget(), MetaModelService.Mode.RELAXED);
-        return !(sortOfObject.isViewModel() || sortOfObject.isEntity())
-                ? "Can only open view models or entities"
-                : null;
-    }
-
-
-
-    /**
-     * The property of the object that was changed.
-     *
-     * <p>
-     * Populated only for audit entries.
-     *
-     * <p>
-     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
-     * subclasses override with the &quot;real&quot; implementation.
-     */
-    @Property(optionality = Optionality.OPTIONAL)
-    @PropertyLayout(hidden = Where.ALL_EXCEPT_STANDALONE_TABLES)
-    @MemberOrder(name="Target",sequence = "21")
-    public String getPropertyId() {
-        return null;
-    }
-
-
-    /**
-     * The value of the property prior to it being changed.
-     *
-     * <p>
-     * Populated only for audit entries.
-     *
-     * <p>
-     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
-     * subclasses override with the &quot;real&quot; implementation.
-     */
-    @Property(optionality = Optionality.OPTIONAL)
-    @PropertyLayout(hidden = Where.ALL_EXCEPT_STANDALONE_TABLES)
-    @MemberOrder(name="Detail",sequence = "6")
-    public String getPreValue() {
-        return null;
-    }
-
-
-    /**
-     * The value of the property after it has changed.
-     *
-     * <p>
-     * Populated only for audit entries.
-     *
-     * <p>
-     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
-     * subclasses override with the &quot;real&quot; implementation.
-     */
-    @Property(optionality = Optionality.MANDATORY)
-    @PropertyLayout(hidden = Where.ALL_EXCEPT_STANDALONE_TABLES)
-    @MemberOrder(name="Detail",sequence = "7")
-    public String getPostValue() {
-        return null;
-    }
-
-
-    @javax.inject.Inject
-    protected BookmarkService bookmarkService;
-
-    @javax.inject.Inject
-    protected MessageService messageService;
-
-    @javax.inject.Inject
-    protected MetaModelService metaModelService;
-
-}
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..ea81d3f
--- /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="Class")
+    @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/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 aa30c57..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,201 +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.
+     * 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>
-     * 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.
-     *
-     * <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[]
 
     /**
@@ -230,7 +160,8 @@ public interface Command extends HasUniqueId {
      * {@link Interaction.Execution#getStartedAt()}.
      */
     // tag::refguide[]
-    Timestamp getStartedAt();                   // <.>
+    @Getter
+    private Timestamp startedAt;                // <.>
     // end::refguide[]
 
     /**
@@ -247,229 +178,170 @@ public interface Command extends HasUniqueId {
      * {@link Interaction.Execution#getCompletedAt()}.
      */
     // tag::refguide[]
-    Timestamp getCompletedAt();                 // <.>
+    @Getter
+    private Timestamp completedAt;              // <.>
     // end::refguide[]
 
     /**
-     * For actions created through the {@link WrapperFactory} and {@link BackgroundCommandService},
-     * captures the parent action.
-     */
-    // tag::refguide[]
-    Command getParent();                        // <.>
-    // 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.
-     *
-     * <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.
+     * Whether this command resulted in a change of state to the system.
      *
      * <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 #isPersistHint() 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);
-
-        /**
-         * <b>NOT API</b>: intended to be called only by the framework.
-         */
-        void setExecutor(final Executor executor);
-
+        public void setLogicalMemberIdentifier(String logicalMemberIdentifier) {
+            Command.this.logicalMemberIdentifier = logicalMemberIdentifier;
+        }
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          */
-        void setExecuteIn(CommandExecuteIn executeIn);
-
+        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..8e50213 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
@@ -30,7 +30,6 @@ 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.inject.ServiceInjector;
 
 import lombok.Getter;
@@ -69,12 +68,6 @@ public class CommandContext {
             serviceInjector.injectServicesInto(command);
         }
     }
-
-    public Optional<Executor> getCurrentExecutor() {
-        return Optional.ofNullable(getCommand())
-                .map(Command::getExecutor);
-    }
-
     // tag::refguide[]
 }
 // end::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 da4e3e4..0000000
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandDefault.java
+++ /dev/null
@@ -1,186 +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 void setExecuteIn(CommandExecuteIn executeIn) {
-            CommandDefault.this.executeIn = executeIn;
-        }
-    };
-
-    @Override
-    public Command.Internal internal() {
-        return INTERNAL;
-    }
-
-}
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..c97685f 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,13 @@ public interface CommandExecutorService {
      * Executes the specified command.
      *
      * @param sudoPolicy
-     * @param commandWithDto
+     * @param command
      * @return - any exception raised by the command.
      */
     // tag::refguide[]
     void executeCommand(
             SudoPolicy sudoPolicy,          // <.>
-            CommandWithDto commandWithDto   // <.>
+            Command command                 // <.>
     );
 
     Bookmark executeCommand(
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
index eb3abce..ef1cf9c 100644
--- 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
@@ -49,7 +49,7 @@ public interface CommandService {
 
     /**
      * &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}
+     * persist it if its {@link Command#getPersistence()} and {@link Command#isSystemStateChanged() persistence hint}
      * indicate that it should be.
      *
      * <p>
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..b96e6d3 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
@@ -35,7 +35,6 @@ 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;
@@ -63,27 +62,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 +95,7 @@ public class ContentMappingServiceForCommandDto implements ContentMappingService
         if (commandDtoProcessor == null) {
             return commandDto;
         }
-        return commandDtoProcessor.process(commandWithDto, commandDto);
+        return commandDtoProcessor.process(command, commandDto);
     }
 
 
@@ -115,7 +114,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,13 +123,6 @@ 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);
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/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 e17dacb..2b2ffa4 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
@@ -58,7 +58,6 @@ 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.i18n.TranslationService;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.publish.PublishedObjects;
@@ -656,7 +655,7 @@ public class IsisConfiguration {
                  * <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
+                 *     memento (obtained using {@link CommandWithDto#getCommandDto()}) as a
                  *     {@link org.apache.isis.schema.cmd.v2.CommandDto}.
                  * </p>
                  *
@@ -843,7 +842,7 @@ public class IsisConfiguration {
                  * <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
+                 *     memento (obtained using {@link CommandWithDto#getCommandDto()}) as a
                  *     {@link org.apache.isis.schema.cmd.v2.CommandDto}.
                  * </p>
                  *
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..8798f14 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,9 +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;
 import org.apache.isis.core.config.IsisConfiguration;
@@ -116,7 +113,7 @@ public class CommandFacetForActionAnnotation extends CommandFacetAbstract {
             final CommandDtoProcessor processor,
             final FacetHolder holder,
             final ServiceInjector servicesInjector) {
-        super(persistence, executeIn, enablement, processor, holder, servicesInjector);
+        super(persistence, 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..dca1c21 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,8 +18,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;
 
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..0232d2c 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;
@@ -40,7 +38,7 @@ public class CommandFacetFromConfiguration extends CommandFacetAbstract {
             final CommandExecuteIn executeIn,
             final FacetHolder holder,
             final ServiceInjector servicesInjector) {
-        super(persistence, executeIn, Enablement.ENABLED, null, holder, servicesInjector);
+        super(persistence, null, holder, servicesInjector);
     }
 
 }
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..314e6d9 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;
@@ -38,18 +35,5 @@ 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/command/CommandFacetForPropertyAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotation.java
index 8a551cb..558ba6a 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,9 +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;
 import org.apache.isis.applib.services.inject.ServiceInjector;
@@ -92,7 +89,7 @@ public class CommandFacetForPropertyAnnotation extends CommandFacetAbstract {
             final FacetHolder holder,
             final CommandDtoProcessor processor,
             final ServiceInjector servicesInjector) {
-        super(persistence, executeIn, enablement, processor, holder, servicesInjector);
+        super(persistence, 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..330775e 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,8 +18,6 @@
  */
 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;
 
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/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_Command.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_Command.java
index f322a8a..deb5634 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,9 +29,6 @@ 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;
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/BackgroundCommandExecution.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/BackgroundCommandExecution.java
index 392b4d6..16a9667 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/BackgroundCommandExecution.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/BackgroundCommandExecution.java
@@ -22,7 +22,6 @@ import java.util.List;
 
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandExecutorService;
-import org.apache.isis.applib.services.command.CommandWithDto;
 import org.apache.isis.core.commons.internal.collections._Lists;
 
 import lombok.val;
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/CommandExecutionAbstract.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/CommandExecutionAbstract.java
index d56cbc7..113fd7f 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/CommandExecutionAbstract.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/background/CommandExecutionAbstract.java
@@ -21,7 +21,6 @@ package org.apache.isis.core.runtimeservices.background;
 import javax.inject.Inject;
 
 import org.apache.isis.applib.services.command.CommandExecutorService;
-import org.apache.isis.applib.services.command.CommandWithDto;
 import org.apache.isis.applib.services.xactn.TransactionService;
 import org.apache.isis.core.runtime.iactn.template.AbstractIsisInteractionTemplate;
 
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandDtoServiceInternalDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandDtoServiceInternalDefault.java
index 12da090..71b5c76 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandDtoServiceInternalDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandDtoServiceInternalDefault.java
@@ -64,8 +64,8 @@ import lombok.val;
 @Qualifier("Default")
 public class CommandDtoServiceInternalDefault implements CommandDtoServiceInternal {
 
-    @Inject private javax.inject.Provider<CommandContext> commandContextProvider;
-    @Inject private BookmarkService bookmarkService;
+    @Inject javax.inject.Provider<CommandContext> commandContextProvider;
+    @Inject BookmarkService bookmarkService;
 
     @Override
     public CommandDto asCommandDto(
@@ -131,13 +131,9 @@ public class CommandDtoServiceInternalDefault implements CommandDtoServiceIntern
             final ObjectAction objectAction,
             final ActionDto actionDto,
             final Can<ManagedObject> argAdapters) {
-        
-        final String actionId = CommandUtil.memberIdentifierFor(objectAction);
-        final ObjectSpecification onType = objectAction.getOnType();
-        final String objectType = onType.getSpecId().asString();
-        final String localId = objectAction.getIdentifier().toNameIdentityString();
-        actionDto.setLogicalMemberIdentifier(objectType + "#" + localId);
-        actionDto.setMemberIdentifier(actionId);
+
+        actionDto.setLogicalMemberIdentifier(CommandUtil.logicalMemberIdentifierFor(objectAction));
+        actionDto.setMemberIdentifier(CommandUtil.memberIdentifierFor(objectAction));
 
         val actionParameters = objectAction.getParameters();
         for (int paramNum = 0; paramNum < actionParameters.size(); paramNum++) {
@@ -161,12 +157,8 @@ public class CommandDtoServiceInternalDefault implements CommandDtoServiceIntern
             final PropertyDto propertyDto,
             final ManagedObject valueAdapter) {
 
-        val actionIdentifier = CommandUtil.memberIdentifierFor(property);
-        val onType = property.getOnType();
-        val objectType = onType.getSpecId().asString();
-        val localId = property.getIdentifier().toNameIdentityString();
-        propertyDto.setLogicalMemberIdentifier(objectType + "#" + localId);
-        propertyDto.setMemberIdentifier(actionIdentifier);
+        propertyDto.setLogicalMemberIdentifier(CommandUtil.logicalMemberIdentifierFor(property));
+        propertyDto.setMemberIdentifier(CommandUtil.memberIdentifierFor(property));
 
         val valueSpec = property.getSpecification();
         val valueType = valueSpec.getCorrespondingClass();
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
index 68fb7a0..ca87863 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
@@ -40,7 +40,6 @@ import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandExecutorService;
-import org.apache.isis.applib.services.command.CommandWithDto;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.iactn.InteractionContext;
 import org.apache.isis.applib.services.sudo.SudoService;
@@ -105,9 +104,9 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
     @Override
     public void executeCommand(
             final CommandExecutorService.SudoPolicy sudoPolicy,
-            final CommandWithDto commandWithDto) {
+            final Command command) {
 
-        final Runnable commandRunnable = ()->executeCommand(commandWithDto);
+        final Runnable commandRunnable = ()->executeCommand(command);
         final Runnable topLevelRunnable;
 
         switch (sudoPolicy) {
@@ -115,7 +114,7 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
             topLevelRunnable = commandRunnable;
             break;
         case SWITCH:
-            val user = commandWithDto.getUser();
+            val user = command.getUsername();
             topLevelRunnable = ()->sudoService.sudo(user, commandRunnable);
             break;
         default:
@@ -126,27 +125,22 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
 
             transactionService.executeWithinTransaction(topLevelRunnable);
 
-            afterCommit(commandWithDto, /*exception*/null);
+            afterCommit(command, /*exception*/null);
 
         } catch (Exception e) {
 
-            val executeIn = commandWithDto.getExecuteIn();
-
-            log.warn("Exception when executing : {} {}", executeIn, commandWithDto.getMemberIdentifier(), e);
-            afterCommit(commandWithDto, e);
+            log.warn("Exception when executing : {}", command.getLogicalMemberIdentifier(), e);
+            afterCommit(command, e);
         }
 
     }
 
-    protected void executeCommand(final CommandWithDto commandWithDto) {
+    protected void executeCommand(final Command command) {
 
         // setup for us by IsisTransactionManager; will have the transactionId of the backgroundCommand
         val interaction = interactionContextProvider.get().getInteraction();
-        val executeIn = commandWithDto.getExecuteIn();
-
-        log.info("Executing: {} {} {} {}", executeIn, commandWithDto.getMemberIdentifier(), commandWithDto.getTimestamp(), commandWithDto.getUniqueId());
 
-        commandWithDto.internal().setExecutor(Command.Executor.BACKGROUND);
+        log.info("Executing: {} {} {}", command.getLogicalMemberIdentifier(), command.getTimestamp(), command.getUniqueId());
 
         // responsibility for setting the Command#startedAt is in the ActionInvocationFacet or
         // PropertySetterFacet, but this is run if the domain object was found.  If the domain object is
@@ -159,12 +153,12 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
                 ? currentExecution.getStartedAt()
                         : clockService.nowAsJavaSqlTimestamp();
 
-        commandWithDto.internal().setStartedAt(startedAt);
+        command.internal().setStartedAt(startedAt);
 
-        final CommandDto dto = commandWithDto.asDto();
+        val dto = command.getCommandDto();
 
-        Bookmark resultBookmark = executeCommand(dto);
-        commandWithDto.internal().setResult(resultBookmark);
+        val resultBookmark = executeCommand(dto);
+        command.internal().setResult(resultBookmark);
     }
 
     @Override
@@ -233,17 +227,17 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
         return null;
     }
 
-    protected void afterCommit(CommandWithDto commandWithDto, Exception exceptionIfAny) {
+    protected void afterCommit(final Command command, final Exception exceptionIfAny) {
 
         val interaction = interactionContextProvider.get().getInteraction();
 
         // it's possible that there is no priorExecution, specifically if there was an exception
         // when performing the action invocation/property edit.  We therefore need to guard that case.
         final Interaction.Execution<?, ?> priorExecution = interaction.getPriorExecution();
-        if (commandWithDto.getStartedAt() == null) {
+        if (command.getStartedAt() == null) {
             // if attempting to commit the xactn threw an error, we will (I think?) have lost this info, so need to
             // capture
-            commandWithDto.internal().setStartedAt(
+            command.internal().setStartedAt(
                     priorExecution != null
                     ? priorExecution.getStartedAt()
                             : clockService.nowAsJavaSqlTimestamp());
@@ -253,12 +247,10 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
                 priorExecution != null
                 ? priorExecution.getCompletedAt()
                         : clockService.nowAsJavaSqlTimestamp();  // close enough...
-                commandWithDto.internal().setCompletedAt(completedAt);
+                command.internal().setCompletedAt(completedAt);
 
                 if(exceptionIfAny != null) {
-                    commandWithDto.internal().setException(_Exceptions.
-                            streamStacktraceLines(exceptionIfAny, 500)
-                            .collect(Collectors.joining("\n")));
+                    command.internal().setException(exceptionIfAny);
                 }
 
     }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandServiceDefault.java
index d9f3c00..527692f 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandServiceDefault.java
@@ -27,12 +27,11 @@ import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.CommandDefault;
 import org.apache.isis.applib.services.command.spi.CommandService;
 
 @Service
 @Named("isisRuntimeServices.CommandServiceDefault")
-@Order(OrderPrecedence.MIDPOINT)
+@Order(OrderPrecedence.LATE)
 @Primary
 @Qualifier("Default")
 public class CommandServiceDefault implements CommandService {
diff --git a/examples/demo/domain/pom.xml b/examples/demo/domain/pom.xml
index 60787ed..4e19164 100644
--- a/examples/demo/domain/pom.xml
+++ b/examples/demo/domain/pom.xml
@@ -109,6 +109,12 @@
             <artifactId>isis-valuetypes-markdown-applib</artifactId>
         </dependency>
 
-    </dependencies>
+		<!-- Extensions -->
+		<dependency>
+			<groupId>org.apache.isis.extensions</groupId>
+			<artifactId>isis-extensions-command-log-impl</artifactId>
+		</dependency>
+
+	</dependencies>
 
 </project>
\ No newline at end of file
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/DemoModule.java b/examples/demo/domain/src/main/java/demoapp/dom/DemoModule.java
index d4b3103..cb7cb7c 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/DemoModule.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/DemoModule.java
@@ -27,6 +27,7 @@ import org.springframework.context.annotation.PropertySources;
 
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.core.runtimeservices.IsisModuleCoreRuntimeServices;
+import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
 import org.apache.isis.extensions.modelannotation.metamodel.IsisModuleExtModelAnnotation;
 import org.apache.isis.extensions.secman.api.SecurityModuleConfig;
 import org.apache.isis.extensions.secman.api.permission.PermissionsEvaluationService;
@@ -38,11 +39,13 @@ import org.apache.isis.testing.fixtures.applib.IsisModuleTestingFixturesApplib;
 @Import({
     IsisModuleCoreRuntimeServices.class,
     IsisModuleJdoDataNucleus5.class,
-    
+
     IsisModuleTestingFixturesApplib.class,
 
     IsisModuleExtModelAnnotation.class, // @Model support
 
+    IsisModuleExtCommandLogImpl.class,
+
 })
 @PropertySources({
     @PropertySource(IsisPresets.H2InMemory),
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandDisabledMetaAnnotation.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandDisabledMetaAnnotation.java
index 5cf894b..21b53f8 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandDisabledMetaAnnotation.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandDisabledMetaAnnotation.java
@@ -7,9 +7,6 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.CommandReification;
-import org.apache.isis.applib.annotation.Property;
-import org.apache.isis.applib.annotation.Publishing;
 
 //tag::class[]
 @Action(command = CommandReification.DISABLED)  // <.>
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.java
index a385c5c..cb9e6bd 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.java
@@ -18,8 +18,6 @@
  */
 package demoapp.dom.annotDomain.Action.command;
 
-import java.util.concurrent.ExecutorService;
-
 import javax.inject.Inject;
 import javax.jdo.annotations.DatastoreIdentity;
 import javax.jdo.annotations.IdGeneratorStrategy;
@@ -28,15 +26,11 @@ import javax.jdo.annotations.PersistenceCapable;
 
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.ActionLayout;
-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.DomainObject;
 import org.apache.isis.applib.annotation.Editing;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.Nature;
 import org.apache.isis.applib.annotation.Property;
-import org.apache.isis.applib.annotation.Publishing;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.wrapper.WrapperFactory;
 import org.apache.isis.applib.services.wrapper.control.AsyncControl;
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.layout.xml
index 8b34302..0e2cf8c 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.layout.xml
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/ActionCommandJdo.layout.xml
@@ -28,8 +28,7 @@
 			</bs3:row>
 			<bs3:row>
 				<bs3:col span="12">
-					<cpt:collection id="foregroundCommands"/>
-					<cpt:collection id="backgroundCommands"/>
+					<cpt:collection id="commands"/>
 				</bs3:col>
 			</bs3:row>
 			<bs3:row>
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_backgroundCommands.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_backgroundCommands.java
deleted file mode 100644
index ab695e5..0000000
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_backgroundCommands.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package demoapp.dom.annotDomain.Action.command.spiimpl;
-
-import java.util.LinkedList;
-
-import javax.inject.Inject;
-
-import org.apache.isis.applib.annotation.Collection;
-import org.apache.isis.applib.services.command.CommandWithDto;
-import org.apache.isis.schema.cmd.v2.CommandDto;
-
-import lombok.val;
-
-import demoapp.dom.annotDomain.Action.command.ActionCommandJdo;
-
-//tag::class[]
-@Collection
-public class ActionCommandJdo_backgroundCommands {
-    // ...
-//end::class[]
-
-    private final ActionCommandJdo actionCommandJdo;
-    public ActionCommandJdo_backgroundCommands(ActionCommandJdo actionCommandJdo) {
-        this.actionCommandJdo = actionCommandJdo;
-    }
-
-    //tag::class[]
-    public LinkedList<CommandDto> coll() {
-        val list = new LinkedList<CommandDto>();
-        commandServiceSpiForActions
-                .streamBackgroundCommands()
-                .map(CommandWithDto::asDto)
-                .forEach(list::push);   // reverse order
-        return list;
-    }
-
-    @Inject
-    private CommandServiceSpiForActions commandServiceSpiForActions;
-}
-//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_clearBackgroundCommands.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_clearBackgroundCommands.java
deleted file mode 100644
index 410674f..0000000
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_clearBackgroundCommands.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package demoapp.dom.annotDomain.Action.command.spiimpl;
-
-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 demoapp.dom.annotDomain.Action.command.ActionCommandJdo;
-
-//tag::class[]
-@Action(
-    semantics = SemanticsOf.IDEMPOTENT
-    , associateWith = "backgroundCommands"
-)
-@ActionLayout(
-    named = "Clear"
-)
-public class ActionCommandJdo_clearBackgroundCommands {
-    // ...
-//end::class[]
-
-    private final ActionCommandJdo actionCommandJdo;
-    public ActionCommandJdo_clearBackgroundCommands(ActionCommandJdo actionCommandJdo) {
-        this.actionCommandJdo = actionCommandJdo;
-    }
-
-
-    //tag::class[]
-    public ActionCommandJdo act() {
-        commandServiceSpiForActions.clearBackgroundCommands();
-        return actionCommandJdo;
-    }
-
-    @Inject
-    private CommandServiceSpiForActions commandServiceSpiForActions;
-}
-//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_clearForegroundCommands.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_clearForegroundCommands.java
deleted file mode 100644
index 3485421..0000000
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_clearForegroundCommands.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package demoapp.dom.annotDomain.Action.command.spiimpl;
-
-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 demoapp.dom.annotDomain.Action.command.ActionCommandJdo;
-
-//tag::class[]
-@Action(
-    semantics = SemanticsOf.IDEMPOTENT
-    , associateWith = "foregroundCommands"
-)
-@ActionLayout(
-    named = "Clear"
-)
-public class ActionCommandJdo_clearForegroundCommands {
-    // ...
-//end::class[]
-
-    private final ActionCommandJdo actionCommandJdo;
-    public ActionCommandJdo_clearForegroundCommands(ActionCommandJdo actionCommandJdo) {
-        this.actionCommandJdo = actionCommandJdo;
-    }
-
-
-    //tag::class[]
-    public ActionCommandJdo act() {
-        commandServiceSpiForActions.clearForegroundCommands();
-        return actionCommandJdo;
-    }
-
-    @Inject
-    private CommandServiceSpiForActions commandServiceSpiForActions;
-}
-//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_foregroundCommands.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_commands.java
similarity index 63%
rename from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_foregroundCommands.java
rename to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_commands.java
index 5c57292..c3fb8c2 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_foregroundCommands.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_commands.java
@@ -5,7 +5,8 @@ import java.util.LinkedList;
 import javax.inject.Inject;
 
 import org.apache.isis.applib.annotation.Collection;
-import org.apache.isis.applib.services.command.CommandWithDto;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
 import lombok.val;
@@ -14,26 +15,25 @@ import demoapp.dom.annotDomain.Action.command.ActionCommandJdo;
 
 //tag::class[]
 @Collection
-public class ActionCommandJdo_foregroundCommands {
+public class ActionCommandJdo_commands {
     // ...
 //end::class[]
 
     private final ActionCommandJdo actionCommandJdo;
-    public ActionCommandJdo_foregroundCommands(ActionCommandJdo actionCommandJdo) {
+    public ActionCommandJdo_commands(ActionCommandJdo actionCommandJdo) {
         this.actionCommandJdo = actionCommandJdo;
     }
 
     //tag::class[]
     public LinkedList<CommandDto> coll() {
         val list = new LinkedList<CommandDto>();
-        commandServiceSpiForActions
-                .streamForegroundCommands()
-                .map(CommandWithDto::asDto)
+        commandJdoRepository.findCompleted()
+                .stream().map(CommandJdo::getCommandDto)
                 .forEach(list::push);   // reverse order
         return list;
     }
 
     @Inject
-    private CommandServiceSpiForActions commandServiceSpiForActions;
+    CommandJdoRepository commandJdoRepository;
 }
 //end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_executeBackgroundCommands.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_executeBackgroundCommands.java
deleted file mode 100644
index 43b0dbc..0000000
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/ActionCommandJdo_executeBackgroundCommands.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package demoapp.dom.annotDomain.Action.command.spiimpl;
-
-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 demoapp.dom.annotDomain.Action.command.ActionCommandJdo;
-
-//tag::class[]
-@Action(
-    semantics = SemanticsOf.IDEMPOTENT
-    , associateWith = "backgroundCommands"
-    , associateWithSequence = "2"
-)
-@ActionLayout(
-    named = "Execute"
-)
-public class ActionCommandJdo_executeBackgroundCommands {
-    // ...
-//end::class[]
-
-    private final ActionCommandJdo actionCommandJdo;
-    public ActionCommandJdo_executeBackgroundCommands(ActionCommandJdo actionCommandJdo) {
-        this.actionCommandJdo = actionCommandJdo;
-    }
-
-
-    //tag::class[]
-    public ActionCommandJdo act() {
-        commandServiceSpiForActions.clearBackgroundCommands();
-        return actionCommandJdo;
-    }
-
-    @Inject
-    private CommandServiceSpiForActions commandServiceSpiForActions;
-}
-//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/CommandServiceSpiForActions.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/CommandServiceSpiForActions.java
deleted file mode 100644
index af62cf8..0000000
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/command/spiimpl/CommandServiceSpiForActions.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package demoapp.dom.annotDomain.Action.command.spiimpl;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Stream;
-
-import javax.inject.Inject;
-
-import org.springframework.core.annotation.Order;
-import org.springframework.stereotype.Service;
-
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.OrderPrecedence;
-import org.apache.isis.applib.services.background.BackgroundCommandService;
-import org.apache.isis.applib.services.clock.ClockService;
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.CommandDefault;
-import org.apache.isis.applib.services.command.CommandWithDto;
-import org.apache.isis.applib.services.command.spi.CommandService;
-import org.apache.isis.applib.util.schema.CommandDtoUtils;
-import org.apache.isis.core.runtimeservices.background.BackgroundCommandExecution;
-import org.apache.isis.core.security.authentication.standard.SimpleSession;
-import org.apache.isis.schema.cmd.v2.CommandDto;
-
-import lombok.val;
-
-@Service
-@Order(OrderPrecedence.EARLY)       // <.>
-public class CommandServiceSpiForActions implements CommandService {
-
-    public static class CommandWithDtoDefault extends CommandDefault implements CommandWithDto {
-        @Override
-        public CommandDto asDto() {
-            return CommandDtoUtils.fromXml(getMemento());
-        }
-    }
-
-    private List<CommandWithDto> foregroundCommands = new ArrayList<>();
-    private List<CommandWithDto> backgroundCommands = new ArrayList<>();
-
-    @Override
-    public Command create() {
-        return new CommandWithDtoDefault();
-    }
-
-    @Override
-    public boolean persistIfPossible(Command command) {
-        return true;
-    }
-
-    @Override
-    public void complete(Command command) {
-        final CommandWithDtoDefault cwdd = (CommandWithDtoDefault) command;
-        if(command.isPersistHint()) {
-            final CommandExecuteIn executeIn = command.getExecuteIn();
-            switch (executeIn) {
-                case FOREGROUND:
-                    foregroundCommands.add((CommandWithDto) command);
-                case BACKGROUND:
-                    backgroundCommands.add((CommandWithDto) command);
-            }
-        }
-    }
-
-    public Stream<CommandWithDto> streamForegroundCommands() {
-        return foregroundCommands.stream();
-    }
-
-    public void clearForegroundCommands() {
-        foregroundCommands.clear();
-    }
-
-    public Stream<CommandWithDto> streamBackgroundCommands() {
-        return backgroundCommands.stream();
-    }
-
-    public void clearBackgroundCommands() {
-        backgroundCommands.clear();
-    }
-
-    public void executeBackgroundCommands() {
-        val execution = new BackgroundCommandExecution() {
-            @Override
-            protected List<? extends Command> findBackgroundCommandsToExecute() {
-                return backgroundCommands;
-            }
-        };
-        val simpleSession = new SimpleSession("sven", Collections.emptyList(), "");
-
-        execution.execute(simpleSession, null);
-        clearBackgroundCommands();
-    }
-
-}
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/IsisModuleExtCommandLogImpl.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/IsisModuleExtCommandLogImpl.java
index 991b53d..21135fa 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/IsisModuleExtCommandLogImpl.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/IsisModuleExtCommandLogImpl.java
@@ -4,19 +4,13 @@ import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 
-import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdoRepository;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 import org.apache.isis.extensions.commandlog.impl.ui.CommandServiceMenu;
 import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScript;
 import org.apache.isis.testing.fixtures.applib.modules.ModuleWithFixtures;
 import org.apache.isis.testing.fixtures.applib.teardown.TeardownFixtureAbstract;
 
-import org.apache.isis.extensions.commandlog.impl.background.BackgroundCommandExecutionFromBackgroundCommandServiceJdo;
-import org.apache.isis.extensions.commandlog.impl.background.BackgroundCommandServiceJdo;
-import org.apache.isis.extensions.commandlog.impl.background.BackgroundCommandServiceJdoRepository;
-
 @Configuration
 @Import({
         // @DomainService's
@@ -24,7 +18,7 @@ import org.apache.isis.extensions.commandlog.impl.background.BackgroundCommandSe
         , BackgroundCommandServiceJdo.class
         , BackgroundCommandServiceJdoRepository.class
         , CommandServiceJdo.class
-        , CommandServiceJdoRepository.class
+        , CommandJdoRepository.class
         , CommandServiceMenu.class
 })
 @ComponentScan(
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandWithDto.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/api/UserDataKeys.java
similarity index 64%
rename from api/applib/src/main/java/org/apache/isis/applib/services/command/CommandWithDto.java
rename to extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/api/UserDataKeys.java
index cd421ea..d603b90 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandWithDto.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/api/UserDataKeys.java
@@ -16,20 +16,19 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.applib.services.command;
+package org.apache.isis.extensions.commandlog.impl.api;
 
-import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
-// tag::refguide[]
-public interface CommandWithDto extends Command {
+import lombok.experimental.UtilityClass;
 
-    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";
+/**
+ * Keys used in {@link CommandDto#getUserData()} to marshall the command's results
+ */
+@UtilityClass
+public class UserDataKeys {
+
+    public static String RESULT = "org.apache.isis.extensions.commandlog.impl.api.UserDataKeys#RESULT";
+    public static String EXCEPTION = "org.apache.isis.extensions.commandlog.impl.api.UserDataKeys#EXCEPTION";
 
-    CommandDto asDto();
 }
-// end::refguide[]
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/background/BackgroundCommandExecutionFromBackgroundCommandServiceJdo.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/background/BackgroundCommandExecutionFromBackgroundCommandServiceJdo.java
deleted file mode 100644
index dc0d1fe..0000000
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/background/BackgroundCommandExecutionFromBackgroundCommandServiceJdo.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package org.apache.isis.extensions.commandlog.impl.background;
-
-import java.util.List;
-
-import javax.inject.Inject;
-
-import org.apache.isis.applib.annotation.DomainService;
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.CommandExecutorService;
-import org.apache.isis.core.runtimeservices.background.BackgroundCommandExecution;
-
-import lombok.extern.log4j.Log4j2;
-
-@DomainService
-@Log4j2
-public class BackgroundCommandExecutionFromBackgroundCommandServiceJdo
-        extends BackgroundCommandExecution {
-
-    public BackgroundCommandExecutionFromBackgroundCommandServiceJdo() {
-        super(CommandExecutorService.SudoPolicy.NO_SWITCH);
-    }
-
-    @Override
-    protected List<? extends Command> findBackgroundCommandsToExecute() {
-        return backgroundCommandRepository.findBackgroundCommandsNotYetStarted();
-    }
-
-    @Inject BackgroundCommandServiceJdoRepository backgroundCommandRepository;
-}
\ No newline at end of file
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/background/BackgroundCommandServiceJdo.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/background/BackgroundCommandServiceJdo.java
deleted file mode 100644
index 637440e..0000000
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/background/BackgroundCommandServiceJdo.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package org.apache.isis.extensions.commandlog.impl.background;
-
-import java.util.UUID;
-
-import javax.inject.Inject;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.DomainService;
-import org.apache.isis.applib.services.background.BackgroundCommandService;
-import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.applib.services.clock.ClockService;
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.factory.FactoryService;
-import org.apache.isis.applib.util.schema.CommandDtoUtils;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdoRepository;
-import org.apache.isis.schema.cmd.v2.CommandDto;
-import org.apache.isis.schema.common.v2.OidDto;
-
-import lombok.extern.log4j.Log4j2;
-
-/**
- * Persists a memento-ized action such that it can be executed asynchronously,
- * for example through a Quartz scheduler (using
- * {@link BackgroundCommandExecutionFromBackgroundCommandServiceJdo}).
- */
-@DomainService
-@Log4j2
-public class BackgroundCommandServiceJdo implements BackgroundCommandService {
-
-    @Override
-    public void schedule(
-            final CommandDto dto,
-            final Command parentCommand,
-            final String targetClassName,
-            final String targetActionName,
-            final String targetArgs) {
-
-        final CommandJdo backgroundCommand =
-                newBackgroundCommand(parentCommand, targetClassName, targetActionName, targetArgs);
-
-        final OidDto firstTarget = dto.getTargets().getOid().get(0);
-        backgroundCommand.setTargetStr(Bookmark.from(firstTarget).toString());
-        backgroundCommand.internal().setMemento(CommandDtoUtils.toXml(dto));
-        backgroundCommand.setMemberIdentifier(dto.getMember().getMemberIdentifier());
-
-        commandServiceJdoRepository.persist(backgroundCommand);
-    }
-
-    private CommandJdo newBackgroundCommand(
-            final Command parentCommand,
-            final String targetClassName,
-            final String targetActionName,
-            final String targetArgs) {
-
-        final CommandJdo backgroundCommand = factoryService.instantiate(CommandJdo.class);
-
-        backgroundCommand.internal().setParent(parentCommand);
-
-        // workaround for ISIS-1472; parentCommand not properly set up if invoked via RO viewer
-        if(parentCommand.getMemberIdentifier() == null) {
-            backgroundCommand.internal().setParent(null);
-        }
-
-        final UUID transactionId = UUID.randomUUID();
-        final String user = parentCommand.getUser();
-
-        backgroundCommand.setTransactionId(transactionId);
-
-        backgroundCommand.internal().setUser(user);
-        backgroundCommand.internal().setTimestamp(clockService.nowAsJavaSqlTimestamp());
-        backgroundCommand.internal().setExecuteIn(CommandExecuteIn.BACKGROUND);
-
-        backgroundCommand.setTargetClass(targetClassName);
-        backgroundCommand.setTargetAction(targetActionName);
-
-        backgroundCommand.internal().setArguments(targetArgs);
-        backgroundCommand.internal().setPersistHint(true);
-
-        return backgroundCommand;
-    }
-
-
-    @Inject CommandServiceJdoRepository commandServiceJdoRepository;
-    @Inject FactoryService factoryService;
-    @Inject ClockService clockService;
-
-}
-
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/background/BackgroundCommandServiceJdoRepository.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/background/BackgroundCommandServiceJdoRepository.java
deleted file mode 100644
index 2195292..0000000
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/background/BackgroundCommandServiceJdoRepository.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package org.apache.isis.extensions.commandlog.impl.background;
-
-import java.util.List;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.core.annotation.Order;
-import org.springframework.stereotype.Service;
-
-import org.apache.isis.applib.annotation.DomainService;
-import org.apache.isis.applib.annotation.OrderPrecedence;
-import org.apache.isis.applib.annotation.Programmatic;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdoRepository;
-
-import lombok.extern.log4j.Log4j2;
-
-/**
- * Provides supporting functionality for querying
- * {@link CommandJdo command} entities that have been persisted
- * to execute in the background.
- *
- * <p>
- * This supporting service with no UI and no side-effects, and is there are no other implementations of the service,
- * thus has been annotated with {@link org.apache.isis.applib.annotation.DomainService}.  This means that there is no
- * need to explicitly register it as a service (eg in <tt>isis.properties</tt>).
- */
-@Service()
-@Named("isisExtensionsCommandLog.BackgroundCommandServiceJdoRepository")
-@Order(OrderPrecedence.MIDPOINT)
-@Qualifier("Jdo")
-@Log4j2
-public class BackgroundCommandServiceJdoRepository {
-
-    public List<CommandJdo> findByParent(CommandJdo parent) {
-        return commandServiceRepository.findBackgroundCommandsByParent(parent);
-    }
-
-    public List<CommandJdo> findBackgroundCommandsNotYetStarted() {
-        return commandServiceRepository.findBackgroundCommandsNotYetStarted();
-    }
-
-    @Inject CommandServiceJdoRepository commandServiceRepository;
-}
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo.java
index 2862b06..7707434 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo.java
@@ -1,67 +1,89 @@
+/*
+ *  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.extensions.commandlog.impl.jdo;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.sql.Timestamp;
 import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
+import java.util.Objects;
 import java.util.UUID;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
+import javax.inject.Inject;
 import javax.jdo.annotations.IdentityType;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.isis.applib.annotation.CommandExecuteIn;
-import org.apache.isis.applib.annotation.CommandPersistence;
 import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.applib.annotation.DomainObjectLayout;
 import org.apache.isis.applib.annotation.Editing;
-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.Where;
-import org.apache.isis.applib.services.DomainChangeAbstract;
-import org.apache.isis.applib.services.HasUsername;
+import org.apache.isis.applib.jaxb.JavaSqlXMLGregorianCalendarMarshalling;
+import org.apache.isis.applib.services.DomainChangeRecord;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.CommandWithDto;
 import org.apache.isis.applib.services.jaxb.JaxbService;
 import org.apache.isis.applib.types.MemberIdentifierType;
-import org.apache.isis.applib.types.TargetActionType;
-import org.apache.isis.applib.types.TargetClassType;
+import org.apache.isis.applib.util.ObjectContracts;
 import org.apache.isis.applib.util.TitleBuffer;
+import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
-import org.apache.isis.extensions.commandlog.impl.jdo.ReplayState;
+import org.apache.isis.extensions.commandlog.impl.api.UserDataKeys;
 import org.apache.isis.schema.cmd.v2.CommandDto;
+import org.apache.isis.schema.cmd.v2.MapDto;
 
 import lombok.Getter;
 import lombok.Setter;
+import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
+/**
+ * A persistent representation of a {@link Command}.
+ *
+ * <p>
+ *     Use cases requiring persistence including auditing, and for replay of
+ *     commands for regression testing purposes.
+ * </p>
+ *
+ * Note that this class doesn't subclass from {@link Command} ({@link Command}
+ * is not an interface).
+ */
 @javax.jdo.annotations.PersistenceCapable(
         identityType=IdentityType.APPLICATION,
-        schema = "isisextcommandlog",
+        schema = "isisExtensionsCommandLog",
         table = "Command")
 @javax.jdo.annotations.Queries( {
     @javax.jdo.annotations.Query(
-            name="findByTransactionId",
+            name="findByUniqueId",
             value="SELECT "
                     + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
-                    + "WHERE transactionId == :transactionId "),
+                    + "WHERE uniqueId == :uniqueId "),
     @javax.jdo.annotations.Query(
-            name="findBackgroundCommandsByParent",
+            name="findByParent",
             value="SELECT "
                     + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
-                    + "WHERE parent == :parent "
-                    + "&& executeIn == 'BACKGROUND'"),
+                    + "WHERE parent == :parent "),
     @javax.jdo.annotations.Query(
             name="findCurrent",
             value="SELECT "
@@ -76,12 +98,11 @@ import lombok.extern.log4j.Log4j2;
                     + "&& executeIn == 'FOREGROUND' "
                     + "ORDER BY this.timestamp DESC"),
     @javax.jdo.annotations.Query(
-            name="findRecentBackgroundByTarget",
+            name="findRecentByTarget",
             value="SELECT "
                     + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
                     + "WHERE targetStr == :targetStr "
-                    + "&& executeIn == 'BACKGROUND' "
-                    + "ORDER BY this.timestamp DESC, transactionId DESC "
+                    + "ORDER BY this.timestamp DESC, uniqueId DESC "
                     + "RANGE 0,30"),
     @javax.jdo.annotations.Query(
             name="findByTargetAndTimestampBetween",
@@ -143,18 +164,10 @@ import lombok.extern.log4j.Log4j2;
                     + "ORDER BY this.timestamp DESC "
                     + "RANGE 0,30"),
     @javax.jdo.annotations.Query(
-            name="findRecentByTarget",
-            value="SELECT "
-                    + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
-                    + "WHERE targetStr == :targetStr "
-                    + "ORDER BY this.timestamp DESC, transactionId DESC "
-                    + "RANGE 0,30"),
-    @javax.jdo.annotations.Query(
-            name="findForegroundFirst",
+            name="findFirst",
             value="SELECT "
                     + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
-                    + "WHERE executeIn == 'FOREGROUND' "
-                    + "   && timestamp   != null "
+                    + "WHERE timestamp   != null "
                     + "   && startedAt   != null "
                     + "   && completedAt != null "
                     + "ORDER BY this.timestamp ASC "
@@ -162,11 +175,10 @@ import lombok.extern.log4j.Log4j2;
         // this should be RANGE 0,1 but results in DataNucleus submitting "FETCH NEXT ROW ONLY"
         // which SQL Server doesn't understand.  However, as workaround, SQL Server *does* understand FETCH NEXT 2 ROWS ONLY
     @javax.jdo.annotations.Query(
-            name="findForegroundSince",
+            name="findSince",
             value="SELECT "
                     + "FROM org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo "
-                    + "WHERE executeIn == 'FOREGROUND' "
-                    + "   && timestamp > :timestamp "
+                    + "WHERE timestamp > :timestamp "
                     + "   && startedAt != null "
                     + "   && completedAt != null "
                     + "ORDER BY this.timestamp ASC"),
@@ -226,11 +238,8 @@ import lombok.extern.log4j.Log4j2;
 )
 @DomainObjectLayout(named = "Command")
 @Log4j2
-public class CommandJdo extends DomainChangeAbstract
-        implements Command, CommandWithDto, HasUsername, Comparable<CommandJdo> {
-
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(CommandJdo.class);
+public class CommandJdo
+        implements DomainChangeRecord, Comparable<CommandJdo> {
 
 
     public static abstract class PropertyDomainEvent<T> extends IsisModuleExtCommandLogImpl.PropertyDomainEvent<CommandJdo, T> { }
@@ -238,95 +247,133 @@ public class CommandJdo extends DomainChangeAbstract
     public static abstract class ActionDomainEvent extends IsisModuleExtCommandLogImpl.ActionDomainEvent<CommandJdo> { }
 
     public CommandJdo() {
-        super(DomainChangeAbstract.ChangeType.COMMAND);
-        this.uniqueId = UUID.randomUUID();
+        this(UUID.randomUUID());
+    }
+
+    private CommandJdo(final UUID uniqueId) {
+        super();
+        this.uniqueId = uniqueId;
+    }
+
+    /**
+     * Intended for use on primary system.
+     *
+     * @param command
+     * @param commandJdoRepository
+     */
+    public CommandJdo(
+            final Command command
+            , final CommandJdoRepository commandJdoRepository) {
+        this();
+
+        setUniqueId(command.getUniqueId());
+        setUsername(command.getUsername());
+        setTimestamp(command.getTimestamp());
+
+        setCommandDto(command.getCommandDto());
+        setTarget(command.getTarget());
+        setLogicalMemberIdentifier(command.getLogicalMemberIdentifier());
+
+        val parent = command.getParent();
+        if(parent != null) {
+            setParent(commandJdoRepository.findByUniqueId(parent.getUniqueId()).orElse(null));
+        }
+
+        setStartedAt(command.getStartedAt());
+        setCompletedAt(command.getCompletedAt());
+
+        setResult(command.getResult());
+
+        setException(command.getException());
+
+        setReplayState(ReplayState.UNDEFINED);
+    }
+
+
+    /**
+     * Intended for use on secondary (replay) system.
+     *
+     * @param commandDto - obtained from the primary system as a representation of a command invocation
+     * @param replayState - controls whether this is to be replayed
+     * @param targetIndex - if the command represents a bulk action, then it is flattened out when replayed; this indicates which target to execute against.
+     */
+    public CommandJdo(final CommandDto commandDto, final ReplayState replayState, final int targetIndex) {
+        this();
+
+        setUniqueId(UUID.fromString(commandDto.getTransactionId()));
+        setUsername(commandDto.getUser());
+        setTimestamp(JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(commandDto.getTimestamp()));
+
+        setCommandDto(commandDto);
+        setTarget(Bookmark.from(commandDto.getTargets().getOid().get(targetIndex)));
+        setLogicalMemberIdentifier(commandDto.getMember().getLogicalMemberIdentifier());
+
+        // the hierarchy of commands calling other commands is only available on the primary system, and is
+        setParent(null);
+
+        setStartedAt(JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(commandDto.getTimings().getStartedAt()));
+        setCompletedAt(JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(commandDto.getTimings().getCompletedAt()));
+
+        set(commandDto, UserDataKeys.RESULT, value -> setResult(Bookmark.parse(value).orElse(null)));
+        set(commandDto, UserDataKeys.EXCEPTION, this::setException);
+
+        setReplayState(replayState);
     }
 
+    private void set(CommandDto commandDto, String key, Consumer<String> consumer) {
+        commandDto.getUserData().getEntry()
+                .stream()
+                .filter(x -> Objects.equals(x.getKey(), UserDataKeys.RESULT))
+                .map(MapDto.Entry::getValue)
+                .findFirst()
+                .ifPresent(consumer::accept);
+    }
 
     public String title() {
         // nb: not thread-safe
         // formats defined in https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
-        final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+        val format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
 
-        final TitleBuffer buf = new TitleBuffer();
+        val buf = new TitleBuffer();
         buf.append(format.format(getTimestamp()));
-        buf.append(" ").append(getMemberIdentifier());
+        buf.append(" ").append(getLogicalMemberIdentifier());
         return buf.toString();
     }
 
 
     public static class UniqueIdDomainEvent extends PropertyDomainEvent<UUID> { }
     @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="false")
-    private UUID uniqueId;
-    /**
-     * {@inheritDoc}
-     */
+    @javax.jdo.annotations.Column(allowsNull="false", length = 36)
     @Property(domainEvent = UniqueIdDomainEvent.class)
-    @Override
-    public UUID getUniqueId() {
-        return uniqueId;
-    }
+    @Getter @Setter
+    private UUID uniqueId;
 
 
-    public static class UserDomainEvent extends PropertyDomainEvent<String> { }
+    public static class UsernameDomainEvent extends PropertyDomainEvent<String> { }
     @javax.jdo.annotations.Column(allowsNull="false", length = 50)
+    @Property(domainEvent = UsernameDomainEvent.class)
+    @Getter @Setter
     private String username;
-    /**
-     * {@inheritDoc}
-     */
-    @Property(domainEvent = UserDomainEvent.class)
-    @Override
-    public String getUsername() {
-        return username;
-    }
 
 
     public static class TimestampDomainEvent extends PropertyDomainEvent<Timestamp> { }
     @javax.jdo.annotations.Persistent
     @javax.jdo.annotations.Column(allowsNull="false")
-    private Timestamp timestamp;
-    /**
-     * {@inheritDoc}
-     */
     @Property(domainEvent = TimestampDomainEvent.class)
-    @Override
-    public Timestamp getTimestamp() {
-        return timestamp;
-    }
+    @Getter @Setter
+    private Timestamp timestamp;
 
 
-    public static class ExecutorDomainEvent extends PropertyDomainEvent<Executor> { }
-    @javax.jdo.annotations.NotPersistent
-    private Executor executor;
-    /**
-     * {@inheritDoc}
-     */
-    @Property(domainEvent = ExecutorDomainEvent.class)
-    @Override
-    public Executor getExecutor() {
-        return executor;
-    }
 
-
-    public static class ExecuteInDomainEvent extends PropertyDomainEvent<CommandExecuteIn> { }
-    @javax.jdo.annotations.Column(allowsNull="false", length = CommandExecuteIn.Type.Meta.MAX_LEN)
-    private CommandExecuteIn executeIn;
-    /**
-     * {@inheritDoc}
-     */
-    @Property(domainEvent = ExecuteInDomainEvent.class)
     @Override
-    public CommandExecuteIn getExecuteIn() {
-        return executeIn;
+    public ChangeType getType() {
+        return ChangeType.COMMAND;
     }
 
 
     public static class ReplayStateDomainEvent extends PropertyDomainEvent<ReplayState> { }
     /**
      * For a replayed command, what the outcome was.
-     *
-     * NOT API.
      */
     @javax.jdo.annotations.Column(allowsNull="true", length=10)
     @Property(domainEvent = ReplayStateDomainEvent.class)
@@ -337,8 +384,6 @@ public class CommandJdo extends DomainChangeAbstract
     public static class ReplayStateFailureReasonDomainEvent extends PropertyDomainEvent<ReplayState> { }
     /**
      * For a {@link ReplayState#FAILED failed} replayed command, what the reason was for the failure.
-     *
-     * <b>NOT API</b>.
      */
     @javax.jdo.annotations.Column(allowsNull="true", length=255)
     @Property(domainEvent = ReplayStateFailureReasonDomainEvent.class)
@@ -352,179 +397,57 @@ public class CommandJdo extends DomainChangeAbstract
 
     public static class ParentDomainEvent extends PropertyDomainEvent<Command> { }
     @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(name="parentTransactionId", allowsNull="true")
-    private Command parent;
-    /**
-     * {@inheritDoc}
-     */
+    @javax.jdo.annotations.Column(name="parentId", allowsNull="true")
     @Property(domainEvent = ParentDomainEvent.class)
     @PropertyLayout(hidden = Where.ALL_TABLES)
-    @Override
-    public Command getParent() {
-        return parent;
-    }
-
-
-    public static class TransactionIdDomainEvent extends PropertyDomainEvent<UUID> { }
-    @javax.jdo.annotations.PrimaryKey
-    @javax.jdo.annotations.Column(allowsNull="false", length = 36)
-    @Setter
-    private UUID transactionId;
-    /**
-     * {@inheritDoc}
-     *
-     * <p>
-     * Implementation notes: copied over from the Isis transaction when the command is persisted.
-     */
-    @Property(domainEvent = TransactionIdDomainEvent.class)
-    @Override
-    public UUID getTransactionId() {
-        return transactionId;
-    }
-
-
-    public static class TargetClassDomainEvent extends PropertyDomainEvent<String> { }
-    @javax.jdo.annotations.Column(allowsNull="false", length = TargetClassType.Meta.MAX_LEN)
-    private String targetClass;
-    /**
-     * {@inheritDoc}
-     */
-    @Property(domainEvent = TargetClassDomainEvent.class)
-    @PropertyLayout(named="Class")
-    @Override
-    public String getTargetClass() {
-        return targetClass;
-    }
-    public void setTargetClass(final String targetClass) {
-        this.targetClass = abbreviated(targetClass, TargetClassType.Meta.MAX_LEN);
-    }
-
-
-    public static class TargetActionDomainEvent extends PropertyDomainEvent<String> { }
-    @javax.jdo.annotations.Column(allowsNull="false", length = TargetActionType.Meta.MAX_LEN)
-    private String targetAction;
-    /**
-     * {@inheritDoc}
-     */
-    @Property(domainEvent = TargetActionDomainEvent.class, optionality = Optionality.MANDATORY)
-    @PropertyLayout(hidden = Where.NOWHERE, named = "Action")
-    @Override
-    public String getTargetAction() {
-        return targetAction;
-    }
-    public void setTargetAction(final String targetAction) {
-        this.targetAction = abbreviated(targetAction, TargetActionType.Meta.MAX_LEN);
-    }
+    @Getter @Setter
+    private CommandJdo parent;
 
 
-    public static class TargetStrDomainEvent extends PropertyDomainEvent<String> { }
+    public static class TargetDomainEvent extends PropertyDomainEvent<String> { }
+    @javax.jdo.annotations.Persistent
     @javax.jdo.annotations.Column(allowsNull="true", length = 2000, name="target")
-    private String targetStr;
-    /**
-     * {@inheritDoc}
-     */
-    @Property(domainEvent = TargetStrDomainEvent.class)
+    @Property(domainEvent = TargetDomainEvent.class)
     @PropertyLayout(hidden = Where.REFERENCES_PARENT, named = "Object")
-    @Override
-    public String getTargetStr() {
-        return targetStr;
-    }
-    @Override
-    public void setTargetStr(String targetStr) {
-        this.targetStr = targetStr;
-    }
+    @Getter @Setter
+    private Bookmark target;
 
-    public static class ArgumentsDomainEvent extends PropertyDomainEvent<String> { }
-    @javax.jdo.annotations.Column(allowsNull="true", jdbcType="CLOB", sqlType="LONGVARCHAR")
-    private String arguments;
-    /**
-     * {@inheritDoc}
-     */
-    @Property(domainEvent = ArgumentsDomainEvent.class)
-    @PropertyLayout(multiLine = 7, hidden = Where.ALL_TABLES)
     @Override
-    public String getArguments() {
-        return arguments;
+    public String getTargetMember() {
+        return getCommandDto().getMember().getLogicalMemberIdentifier();
     }
 
-
-    public static class MemberIdentifierDomainEvent extends PropertyDomainEvent<String> { }
-    @javax.jdo.annotations.Column(allowsNull="false", length = MemberIdentifierType.Meta.MAX_LEN)
-    private String memberIdentifier;
-    /**
-     * {@inheritDoc}
-     */
-    @Property(domainEvent = MemberIdentifierDomainEvent.class)
+    public static class LogicalMemberIdentifierDomainEvent extends PropertyDomainEvent<String> { }
+    @Property(domainEvent = LogicalMemberIdentifierDomainEvent.class)
     @PropertyLayout(hidden = Where.ALL_TABLES)
-    @Override
-    public String getMemberIdentifier() {
-        return memberIdentifier;
-    }
-    public void setMemberIdentifier(final String memberIdentifier) {
-        this.memberIdentifier = abbreviated(memberIdentifier, MemberIdentifierType.Meta.MAX_LEN);
-    }
+    @javax.jdo.annotations.Column(allowsNull="false", length = MemberIdentifierType.Meta.MAX_LEN)
+    @Getter @Setter
+    private String logicalMemberIdentifier;
 
 
-    public static class MementoDomainEvent extends PropertyDomainEvent<String> { }
+    public static class CommandDtoDomainEvent extends PropertyDomainEvent<CommandDto> { }
+    @javax.jdo.annotations.Persistent
     @javax.jdo.annotations.Column(allowsNull="true", jdbcType="CLOB")
-    private String memento;
-    /**
-     * {@inheritDoc}
-     */
-    @Property(domainEvent = MementoDomainEvent.class)
-    @PropertyLayout(multiLine = 9, hidden = Where.ALL_TABLES)
-    @Override
-    public String getMemento() {
-        return memento;
-    }
-
-
-    // locally cached
-    private transient CommandDto commandDto;
-
-    @Override
-    public CommandDto asDto() {
-        if(commandDto == null) {
-            this.commandDto = buildCommandDto();
-        }
-        return this.commandDto;
-    }
-
-    private CommandDto buildCommandDto() {
-        if(getMemento() == null) {
-            return null;
-        }
-
-        return jaxbService.fromXml(CommandDto.class, getMemento());
-    }
+    @Property(domainEvent = CommandDtoDomainEvent.class)
+    @PropertyLayout(multiLine = 9)
+    @Getter @Setter
+    private CommandDto commandDto;
 
 
     public static class StartedAtDomainEvent extends PropertyDomainEvent<Timestamp> { }
     @javax.jdo.annotations.Persistent
     @javax.jdo.annotations.Column(allowsNull="true")
-    private Timestamp startedAt;
-    /**
-     * {@inheritDoc}
-     */
     @Property(domainEvent = StartedAtDomainEvent.class)
-    @Override
-    public Timestamp getStartedAt() {
-        return startedAt;
-    }
+    @Getter @Setter
+    private Timestamp startedAt;
 
 
     public static class CompletedAtDomainEvent extends PropertyDomainEvent<Timestamp> { }
     @javax.jdo.annotations.Persistent
     @javax.jdo.annotations.Column(allowsNull="true")
-    private Timestamp completedAt;
-    /**
-     * {@inheritDoc}
-     */
     @Property(domainEvent = CompletedAtDomainEvent.class)
-    @Override
-    public Timestamp getCompletedAt() {
-        return completedAt;
-    }
+    @Getter @Setter
+    private Timestamp completedAt;
 
 
     public static class DurationDomainEvent extends PropertyDomainEvent<BigDecimal> { }
@@ -534,6 +457,7 @@ public class CommandJdo extends DomainChangeAbstract
      * <p>
      * Populated only if it has {@link #getCompletedAt() completed}.
      */
+    @javax.jdo.annotations.NotPersistent
     @javax.validation.constraints.Digits(integer=5, fraction=3)
     @Property(domainEvent = DurationDomainEvent.class)
     public BigDecimal getDuration() {
@@ -560,8 +484,8 @@ public class CommandJdo extends DomainChangeAbstract
         }
         if(getException() != null) {
             return "EXCEPTION";
-        } 
-        if(getResultStr() != null) {
+        }
+        if(getResult() != null) {
             return "OK";
         } else {
             return "OK (VOID)";
@@ -569,45 +493,37 @@ public class CommandJdo extends DomainChangeAbstract
     }
 
 
-    @Programmatic
-    @Override
-    public Bookmark getResult() {
-        return bookmarkFor(getResultStr());
-    }
-    @Programmatic
-    public void setResult(final Bookmark result) {
-        setResultStr(asString(result));
-    }
-
-
-    public static class ResultStrDomainEvent extends PropertyDomainEvent<String> { }
+    public static class ResultDomainEvent extends PropertyDomainEvent<String> { }
+    @javax.jdo.annotations.Persistent
     @javax.jdo.annotations.Column(allowsNull="true", length = 2000, name="result")
-    @Property(domainEvent = ResultStrDomainEvent.class)
+    @Property(domainEvent = ResultDomainEvent.class)
     @PropertyLayout(hidden = Where.ALL_TABLES, named = "Result Bookmark")
     @Getter @Setter
-    private String resultStr;
+    private Bookmark result;
 
 
     public static class ExceptionDomainEvent extends PropertyDomainEvent<String> { }
     /**
      * Stack trace of any exception that might have occurred if this interaction/transaction aborted.
-     * 
+     *
      * <p>
      * Not part of the applib API, because the default implementation is not persistent
      * and so there's no object that can be accessed to be annotated.
      */
     @javax.jdo.annotations.Column(allowsNull="true", jdbcType="CLOB")
-    private String exception;
-    /**
-     * {@inheritDoc}
-     */
     @Property(domainEvent = ExceptionDomainEvent.class)
     @PropertyLayout(hidden = Where.ALL_TABLES, multiLine = 5, named = "Exception (if any)")
-    @Override
-    public String getException() {
-        return exception;
+    @Getter
+    private String exception;
+    public void setException(String exception) {
+        this.exception = exception;
+    }
+    public void setException(final Throwable exception) {
+        val stackTraceStr =
+                _Exceptions.streamStacktraceLines(exception, 1000)
+                .collect(Collectors.joining("\n"));
+        setException(stackTraceStr);
     }
-
 
     public static class IsCausedExceptionDomainEvent extends PropertyDomainEvent<Boolean> { }
     @javax.jdo.annotations.NotPersistent
@@ -618,204 +534,56 @@ public class CommandJdo extends DomainChangeAbstract
     }
 
 
-
-    private final LinkedList<org.apache.isis.applib.events.domain.ActionDomainEvent<?>> actionDomainEvents = new LinkedList<>();
-    @Programmatic
-    public org.apache.isis.applib.events.domain.ActionDomainEvent<?> peekActionDomainEvent() {
-        return actionDomainEvents.isEmpty()? null: actionDomainEvents.getLast();
-    }
-    @Programmatic
-    public void pushActionDomainEvent(final org.apache.isis.applib.events.domain.ActionDomainEvent<?> event) {
-        if(peekActionDomainEvent() == event) {
-            return;
-        }
-        this.actionDomainEvents.add(event);
-    }
-    @Programmatic
-    public org.apache.isis.applib.events.domain.ActionDomainEvent<?> popActionDomainEvent() {
-        return !actionDomainEvents.isEmpty()
-                ? actionDomainEvents.removeLast() : null;
-    }
-    @Programmatic
-    public List<org.apache.isis.applib.events.domain.ActionDomainEvent<?>> flushActionDomainEvents() {
-        final List<org.apache.isis.applib.events.domain.ActionDomainEvent<?>> events =
-                Collections.unmodifiableList(new ArrayList<>(actionDomainEvents));
-        actionDomainEvents.clear();
-        return events;
-    }
-
-
-    private final Map<String, AtomicInteger> sequenceByName = new HashMap<>();
-    @Programmatic
-    public int next(final String sequenceAbbr) {
-        AtomicInteger next = sequenceByName.get(sequenceAbbr);
-        if(next == null) {
-            next = new AtomicInteger(0);
-            sequenceByName.put(sequenceAbbr, next);
-        } else {
-            next.incrementAndGet();
-        }
-        return next.get();
+    @Override
+    public String toString() {
+        return ObjectContracts
+                .toString("uniqueId", CommandJdo::getUniqueId)
+                .thenToString("username", CommandJdo::getUsername)
+                .thenToString("timestamp", CommandJdo::getTimestamp)
+                .thenToString("target", CommandJdo::getTarget)
+                .thenToString("logicalMemberIdentifier", CommandJdo::getLogicalMemberIdentifier)
+                .thenToStringOmitIfAbsent("startedAt", CommandJdo::getStartedAt)
+                .thenToStringOmitIfAbsent("completedAt", CommandJdo::getCompletedAt)
+                .toString(this);
     }
 
-
-
-    @javax.jdo.annotations.NotPersistent
-    @Programmatic
-    private CommandPersistence persistence;
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public CommandPersistence getPersistence() {
-        return persistence;
+    public int compareTo(final CommandJdo other) {
+        return this.getTimestamp().compareTo(other.getTimestamp());
     }
 
 
-    @javax.jdo.annotations.NotPersistent
-    @Programmatic
-    private boolean persistHint;
     /**
-     * {@inheritDoc}
+     * @return in seconds, to 3 decimal places.
      */
-    @Override
-    public boolean isPersistHint() {
-        return persistHint;
-    }
-
-
-    boolean shouldPersist() {
-        switch (getPersistence()) {
-            case PERSISTED:
-                return true;
-            case IF_HINTED:
-                return isPersistHint();
-            default:
-                return false;
+    private static BigDecimal durationBetween(Timestamp startedAt, Timestamp completedAt) {
+        if (completedAt == null) {
+            return null;
+        } else {
+            long millis = completedAt.getTime() - startedAt.getTime();
+            return toSeconds(millis);
         }
     }
 
+    private static final BigDecimal DIVISOR = new BigDecimal(1000);
 
-    private final Command.Internal INTERNAL = new Command.Internal() {
-        @Override
-        public void setMemberIdentifier(String actionIdentifier) {
-            CommandJdo.this.memberIdentifier = actionIdentifier;
-        }
-        @Override
-        public void setTargetClass(String targetClass) {
-            CommandJdo.this.targetClass = targetClass;
-        }
-        @Override
-        public void setTargetAction(String targetAction) {
-            CommandJdo.this.targetAction = targetAction;
-        }
-        @Override
-        public void setArguments(String arguments) {
-            CommandJdo.this.arguments = arguments;
-        }
-        @Override
-        public void setMemento(String memento) {
-            CommandJdo.this.memento = memento;
-        }
-        @Override
-        public void setTarget(Bookmark target) {
-            CommandJdo.this.setTarget(target);
-        }
-        @Override
-        public void setTimestamp(Timestamp timestamp) {
-            CommandJdo.this.timestamp = timestamp;
-        }
-        @Override
-        public void setStartedAt(Timestamp startedAt) {
-            CommandJdo.this.startedAt = startedAt;
-        }
-        @Override
-        public void setCompletedAt(final Timestamp completed) {
-            CommandJdo.this.completedAt = completed;
-        }
-        @Override
-        public void setUser(String user) {
-            CommandJdo.this.username = user;
-        }
-        @Override
-        public void setParent(Command parent) {
-            CommandJdo.this.parent = parent;
-        }
-        @Override
-        public void setResult(final Bookmark result) {
-            CommandJdo.this.setResult(result);
-        }
-        @Override
-        public void setException(final String exceptionStackTrace) {
-            CommandJdo.this.exception = exceptionStackTrace;
-        }
-        @Override
-        public void setPersistence(CommandPersistence persistence) {
-            CommandJdo.this.persistence = persistence;
-        }
-        @Override
-        public void setPersistHint(boolean persistHint) {
-            CommandJdo.this.persistHint = persistHint;
-        }
-        @Override
-        public void setExecutor(Executor executor) {
-            CommandJdo.this.executor = executor;
-        }
-        @Override
-        public void setExecuteIn(CommandExecuteIn executeIn) {
-            CommandJdo.this.executeIn = executeIn;
-        }
-    };
-
-    @Override
-    public Command.Internal internal() {
-        return INTERNAL;
+    private static BigDecimal toSeconds(long millis) {
+        return new BigDecimal(millis)
+                    .divide(DIVISOR, RoundingMode.HALF_EVEN)
+                    .setScale(3, RoundingMode.HALF_EVEN);
     }
 
 
     @Override
-    public String toString() {
-        return "CommandJdo{" +
-                "targetStr='" + targetStr + '\'' +
-                ", memberIdentifier='" + memberIdentifier + '\'' +
-                ", username='" + username + '\'' +
-                ", startedAt=" + startedAt +
-                ", completedAt=" + completedAt +
-                ", transactionId=" + transactionId +
-                '}';
+    public String getPreValue() {
+        return null;
     }
 
     @Override
-    public int compareTo(final CommandJdo other) {
-        return this.getTimestamp().compareTo(other.getTimestamp());
-    }
-
-
-    private static String abbreviated(String str, int maxLength) {
-        return str != null
-                ? (str.length() < maxLength ? str : str.substring(0, maxLength - 3) + "...")
-                : null;
-    }
-
-    private static Bookmark bookmarkFor(String str) {
-        return Bookmark.parse(str).orElse(null);
-    }
-
-    private static String asString(Bookmark bookmark) {
-        return bookmark != null ? bookmark.toString() : null;
-    }
-
-    private static BigDecimal durationBetween(Timestamp startedAt, Timestamp completedAt) {
-        if (completedAt == null) {
-            return null;
-        } else {
-            long millis = completedAt.getTime() - startedAt.getTime();
-            return (new BigDecimal(millis)).divide(new BigDecimal(1000)).setScale(3, RoundingMode.HALF_EVEN);
-        }
+    public String getPostValue() {
+        return null;
     }
 
-
-    @javax.inject.Inject
-    JaxbService jaxbService;
+    @Inject JaxbService jaxbService;
 
 }
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandServiceJdoRepository.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdoRepository.java
similarity index 76%
rename from extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandServiceJdoRepository.java
rename to extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdoRepository.java
index 61eae44..37b021c 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandServiceJdoRepository.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdoRepository.java
@@ -1,3 +1,21 @@
+/*
+ *  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.extensions.commandlog.impl.jdo;
 
 import java.sql.Timestamp;
@@ -25,7 +43,6 @@ import org.apache.isis.applib.query.QueryDefault;
 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.services.command.CommandWithDto;
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
 import org.apache.isis.persistence.jdo.applib.services.IsisJdoSupport_v3_2;
@@ -43,11 +60,11 @@ import lombok.extern.log4j.Log4j2;
  * {@link CommandJdo command} entities.
  */
 @Service
-@Named("isisExtensionsCommandLog.CommandServiceJdoRepository")
+@Named("isisExtensionsCommandLog.CommandJdoRepository")
 @Order(OrderPrecedence.MIDPOINT)
 @Qualifier("Jdo")
 @Log4j2
-public class CommandServiceJdoRepository {
+public class CommandJdoRepository {
 
     public List<CommandJdo> findByFromAndTo(
             final LocalDate from, final LocalDate to) {
@@ -80,12 +97,19 @@ public class CommandServiceJdoRepository {
     }
 
 
-    public Optional<CommandJdo> findByTransactionId(final UUID transactionId) {
+    public Optional<CommandJdo> findByUniqueId(final UUID transactionId) {
         persistCurrentCommandIfRequired();
         return repositoryService.firstMatch(
                 new QueryDefault<>(CommandJdo.class,
-                        "findByTransactionId", 
-                        "transactionId", transactionId));
+                        "findByUniqueId",
+                        "uniqueId", transactionId));
+    }
+
+    public List<CommandJdo> findByParent(final CommandJdo parent) {
+        return repositoryService.allMatches(
+                new QueryDefault<>(CommandJdo.class,
+                        "findByParent",
+                        "parent", parent));
     }
 
 
@@ -104,14 +128,11 @@ public class CommandServiceJdoRepository {
 
 
     private void persistCurrentCommandIfRequired() {
-        if(commandContextProvider == null || commandService == null) {
+        if(commandContextProvider == null) {
             return;
         } 
         final Command command = commandContextProvider.get().getCommand();
-        final CommandJdo commandJdo = commandService.asUserInitiatedCommandJdo(command);
-        if(commandJdo == null) {
-            return;
-        }
+        final CommandJdo commandJdo = new CommandJdo(command, this);
         repositoryService.persist(commandJdo);
     }
 
@@ -173,13 +194,6 @@ public class CommandServiceJdoRepository {
     }
 
 
-    public List<CommandJdo> findRecentBackgroundByTarget(Bookmark target) {
-        final String targetStr = target.toString();
-        return repositoryService.allMatches(
-                new QueryDefault<>(CommandJdo.class, "findRecentBackgroundByTarget", "targetStr", targetStr));
-    }
-
-
     /**
      * Intended to support the replay of commands on a slave instance of the application.
      *
@@ -202,20 +216,20 @@ public class CommandServiceJdoRepository {
      *
      * @return
      */
-    public List<CommandJdo> findForegroundSince(final UUID transactionId, final Integer batchSize) {
+    public List<CommandJdo> findSince(final UUID transactionId, final Integer batchSize) {
         if(transactionId == null) {
-            return findForegroundFirst();
+            return findFirst();
         }
         final CommandJdo from = findByTransactionIdElseNull(transactionId);
         if(from == null) {
             return null;
         }
-        return findForegroundSince(from.getTimestamp(), batchSize);
+        return findSince(from.getTimestamp(), batchSize);
     }
 
-    private List<CommandJdo> findForegroundFirst() {
+    private List<CommandJdo> findFirst() {
         Optional<CommandJdo> firstCommandIfAny = repositoryService.firstMatch(
-                new QueryDefault<>(CommandJdo.class, "findForegroundFirst"));
+                new QueryDefault<>(CommandJdo.class, "findFirst"));
         return firstCommandIfAny
                 .map(Collections::singletonList)
                 .orElse(Collections.emptyList());
@@ -232,10 +246,10 @@ public class CommandServiceJdoRepository {
         return q.executeUnique();
     }
 
-    private List<CommandJdo> findForegroundSince(final Timestamp timestamp, final Integer batchSize) {
+    private List<CommandJdo> findSince(final Timestamp timestamp, final Integer batchSize) {
         val q = new QueryDefault<>(
                 CommandJdo.class,
-                "findForegroundSince",
+                "findSince",
                 "timestamp", timestamp);
 
         // DN generates incorrect SQL for SQL Server if count set to 1; so we set to 2 and then trim
@@ -258,8 +272,9 @@ public class CommandServiceJdoRepository {
 
         return replayableHwm
                 .orElseGet(() -> {
-            // otherwise, the most recent completed command, run in the foreground
-            // on the slave, this corresponds to a command restored from a copy of the production database
+            // otherwise, the most recent completed command, run on the slave,
+            // this corresponds to a command restored from a copy of
+            // the production database
             Optional<CommandJdo> restoredFromDbHwm = repositoryService.firstMatch(
                     new QueryDefault<>(CommandJdo.class, "findForegroundHwm"));
 
@@ -276,14 +291,6 @@ public class CommandServiceJdoRepository {
     }
 
 
-    @Programmatic
-    public List<CommandJdo> findBackgroundCommandsByParent(final CommandJdo parent) {
-        return repositoryService.allMatches(
-                new QueryDefault<>(CommandJdo.class,
-                        "findBackgroundCommandsByParent",
-                        "parent", parent));
-    }
-
 
     public List<CommandJdo> findReplayedOnSlave() {
         return repositoryService.allMatches(
@@ -312,22 +319,16 @@ public class CommandServiceJdoRepository {
 
         final CommandJdo commandJdo = new CommandJdo();
 
-        commandJdo.setTransactionId(UUID.fromString(dto.getTransactionId()));
-        commandJdo.internal().setTimestamp(JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(dto.getTimestamp()));
-        commandJdo.internal().setUser(dto.getUser());
-        commandJdo.internal().setExecuteIn(org.apache.isis.applib.annotation.CommandExecuteIn.REPLAYABLE);
-
-        commandJdo.setTargetClass(CommandDtoUtils.getUserData(dto, CommandWithDto.USERDATA_KEY_TARGET_CLASS));
-        commandJdo.setTargetAction(CommandDtoUtils.getUserData(dto, CommandWithDto.USERDATA_KEY_TARGET_ACTION));
-        commandJdo.internal().setArguments(CommandDtoUtils.getUserData(dto, CommandWithDto.USERDATA_KEY_ARGUMENTS));
+        commandJdo.setUniqueId(UUID.fromString(dto.getTransactionId()));
+        commandJdo.setTimestamp(JavaSqlXMLGregorianCalendarMarshalling.toTimestamp(dto.getTimestamp()));
+        commandJdo.setUsername(dto.getUser());
 
         commandJdo.setReplayState(ReplayState.PENDING);
-        commandJdo.internal().setPersistHint(true);
 
         final OidDto firstTarget = dto.getTargets().getOid().get(0);
-        commandJdo.setTargetStr(Bookmark.from(firstTarget).toString());
-        commandJdo.internal().setMemento(CommandDtoUtils.toXml(dto));
-        commandJdo.setMemberIdentifier(dto.getMember().getMemberIdentifier());
+        commandJdo.setTarget(Bookmark.from(firstTarget));
+        commandJdo.setCommandDto(dto);
+        commandJdo.setLogicalMemberIdentifier(dto.getMember().getLogicalMemberIdentifier());
 
         persist(commandJdo);
 
@@ -335,37 +336,11 @@ public class CommandServiceJdoRepository {
     }
 
     public void persist(final CommandJdo commandJdo) {
-        withSafeTargetStr(commandJdo);
-        withSafeResultStr(commandJdo);
         repositoryService.persist(commandJdo);
     }
 
-    public void persistIfHinted(final CommandJdo commandJdo) {
-        withSafeTargetStr(commandJdo);
-        withSafeResultStr(commandJdo);
-        if(commandJdo.shouldPersist()) {
-            repositoryService.persist(commandJdo);
-        }
-    }
-
-    private static void withSafeTargetStr(final CommandJdo commandJdo) {
-        if (tooLong(commandJdo.getTargetStr())) {
-            commandJdo.setTargetStr(null);
-        }
-    }
-    private static void withSafeResultStr(final CommandJdo commandJdo) {
-        if (tooLong(commandJdo.getResultStr())) {
-            commandJdo.setResultStr(null);
-        }
-    }
-
-    private static boolean tooLong(final String str) {
-        return str != null && str.length() > 2000;
-    }
-
 
 
-    @Inject CommandServiceJdo commandService;
     @Inject Provider<CommandContext> commandContextProvider;
     @Inject RepositoryService repositoryService;
     @Inject IsisJdoSupport_v3_2 isisJdoSupport;
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_childCommands.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_childCommands.java
index d30d566..2db6437 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_childCommands.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_childCommands.java
@@ -1,3 +1,21 @@
+/*
+ *  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.extensions.commandlog.impl.jdo;
 
 import java.util.List;
@@ -6,7 +24,6 @@ import org.apache.isis.applib.annotation.Collection;
 import org.apache.isis.applib.annotation.CollectionLayout;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
-import org.apache.isis.extensions.commandlog.impl.background.BackgroundCommandServiceJdoRepository;
 
 
 @Collection(domainEvent = CommandJdo_childCommands.CollectionDomainEvent.class)
@@ -23,10 +40,10 @@ public class CommandJdo_childCommands {
 
     @MemberOrder(sequence = "100.100")
     public List<CommandJdo> coll() {
-        return backgroundCommandRepository.findByParent(commandJdo);
+        return commandJdoRepository.findByParent(commandJdo);
     }
 
     @javax.inject.Inject
-    private BackgroundCommandServiceJdoRepository backgroundCommandRepository;
+    private CommandJdoRepository commandJdoRepository;
     
 }
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_openResultObject.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_openResultObject.java
index 4399841..24689de 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_openResultObject.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_openResultObject.java
@@ -1,3 +1,21 @@
+/*
+ *  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.extensions.commandlog.impl.jdo;
 
 import org.apache.isis.applib.annotation.Action;
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_retry.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_retry.java
index 7411b97..d251482 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_retry.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_retry.java
@@ -1,3 +1,21 @@
+/*
+ *  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.extensions.commandlog.impl.jdo;
 
 import java.util.Arrays;
@@ -7,88 +25,37 @@ import java.util.List;
 import javax.inject.Inject;
 
 import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.CommandExecuteIn;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.command.CommandContext;
+import org.apache.isis.applib.services.command.CommandExecutorService;
 import org.apache.isis.applib.services.jaxb.JaxbService;
+import org.apache.isis.applib.util.schema.CommandDtoUtils;
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
-import org.apache.isis.extensions.commandlog.impl.background.BackgroundCommandServiceJdo;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
+import lombok.val;
+
 @Action(
     semantics = SemanticsOf.NON_IDEMPOTENT_ARE_YOU_SURE
     , domainEvent = CommandJdo_retry.ActionDomainEvent.class
 )
 public class CommandJdo_retry {
 
-    public static enum Mode {
-        SCHEDULE_NEW,
-        REUSE
-    }
-
     private final CommandJdo commandJdo;
     public CommandJdo_retry(CommandJdo commandJdo) {
         this.commandJdo = commandJdo;
     }
 
-
     public static class ActionDomainEvent extends IsisModuleExtCommandLogImpl.ActionDomainEvent<CommandJdo_retry> { }
     @MemberOrder(name = "executeIn", sequence = "1")
-    public CommandJdo act(final Mode mode) {
-
-        switch (mode) {
-        case SCHEDULE_NEW:
-            final String memento = commandJdo.getMemento();
-            final CommandDto dto = jaxbService.fromXml(CommandDto.class, memento);
-            backgroundCommandServiceJdo.schedule(
-                    dto, commandContext.getCommand(), commandJdo.getTargetClass(), commandJdo.getTargetAction(), commandJdo.getArguments());
-            break;
-        case REUSE:
-            // will cause it to be picked up next time around
-            commandJdo.internal().setStartedAt(null);
-            commandJdo.internal().setException(null);
-            commandJdo.internal().setCompletedAt(null);
-            commandJdo.setResult(null);
-            commandJdo.setReplayState(null);
-            break;
-        default:
-            // shouldn't occur
-            throw new IllegalStateException(String.format("Probable framework error, unknown mode: %s", mode));
-        }
-        return commandJdo;
-    }
+    public CommandJdo act() {
 
-    public List<Mode> choices0Act() {
-        CommandExecuteIn executeIn = commandJdo.getExecuteIn();
-        switch (executeIn){
-            case FOREGROUND:
-            case BACKGROUND:
-                return Arrays.asList(Mode.SCHEDULE_NEW, Mode.REUSE);
-            case REPLAYABLE:
-                return Collections.singletonList(Mode.REUSE);
-            default:
-                // shouldn't occur
-                throw new IllegalStateException(String.format("Probable framework error, unknown executeIn: %s", executeIn));
-        }
-    }
+        val dto = commandJdo.getCommandDto();
+        commandExecutorService.executeCommand(dto);
 
-    public Mode default0Act() {
-        return choices0Act().get(0);
-    }
-    public String disableAct() {
-        if (!commandJdo.isComplete()) {
-            return "Not yet completed";
-        }
-        return null;
+        return commandJdo;
     }
 
-
-    @Inject
-    CommandContext commandContext;
-    @Inject
-    BackgroundCommandServiceJdo backgroundCommandServiceJdo;
-    @Inject
-    JaxbService jaxbService;
-
+    @Inject CommandExecutorService commandExecutorService;
 }
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_siblingCommands.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_siblingCommands.java
index 1f31cb6..c01a210 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_siblingCommands.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo_siblingCommands.java
@@ -1,14 +1,33 @@
+/*
+ *  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.extensions.commandlog.impl.jdo;
 
 import java.util.Collections;
 import java.util.List;
 
+import javax.inject.Inject;
+
 import org.apache.isis.applib.annotation.Collection;
 import org.apache.isis.applib.annotation.CollectionLayout;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
-import org.apache.isis.extensions.commandlog.impl.background.BackgroundCommandServiceJdoRepository;
 
 @Collection(domainEvent = CommandJdo_siblingCommands.CollectionDomainEvent.class)
 @CollectionLayout(defaultView = "table")
@@ -24,18 +43,16 @@ public class CommandJdo_siblingCommands {
 
     @MemberOrder(sequence = "100.110")
     public List<CommandJdo> coll() {
-        final Command parent = commandJdo.getParent();
-        if(!(parent instanceof CommandJdo)) {
+        final CommandJdo parentJdo = commandJdo.getParent();
+        if(parentJdo == null) {
             return Collections.emptyList();
         }
-        final CommandJdo parentJdo = (CommandJdo) parent;
-        final List<CommandJdo> siblingCommands = backgroundCommandRepository.findByParent(parentJdo);
+        final List<CommandJdo> siblingCommands = commandJdoRepository.findByParent(parentJdo);
         siblingCommands.remove(commandJdo);
         return siblingCommands;
     }
 
 
-    @javax.inject.Inject
-    private BackgroundCommandServiceJdoRepository backgroundCommandRepository;
+    @Inject CommandJdoRepository commandJdoRepository;
     
 }
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandServiceJdo.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandServiceJdo.java
deleted file mode 100644
index 75e2dd2..0000000
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandServiceJdo.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package org.apache.isis.extensions.commandlog.impl.jdo;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-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.CommandExecuteIn;
-import org.apache.isis.applib.annotation.CommandPersistence;
-import org.apache.isis.applib.annotation.DomainService;
-import org.apache.isis.applib.annotation.OrderPrecedence;
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.Command.Executor;
-import org.apache.isis.applib.services.command.spi.CommandService;
-import org.apache.isis.applib.services.factory.FactoryService;
-import org.apache.isis.applib.services.repository.RepositoryService;
-
-import lombok.extern.log4j.Log4j2;
-
-@Service
-@Named("isisExtensionsCommandLog.CommandServiceJdo")
-@Order(OrderPrecedence.MIDPOINT)
-@Qualifier("Jdo")
-@Log4j2
-public class CommandServiceJdo implements CommandService {
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Command create() {
-        CommandJdo command = factoryService.instantiate(CommandJdo.class);
-        command.internal().setExecutor(Executor.OTHER);
-        command.internal().setPersistence(CommandPersistence.IF_HINTED);
-        return command;
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void complete(final Command command) {
-        final CommandJdo commandJdo = asUserInitiatedCommandJdo(command);
-        if(commandJdo == null) {
-            return;
-        }
-        commandServiceJdoRepository.persistIfHinted(commandJdo);
-
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean persistIfPossible(Command command) {
-        if(!(command instanceof CommandJdo)) {
-            // ought not to be the case, since this service created the object in the #create() method
-            return false;
-        }
-        final CommandJdo commandJdo = (CommandJdo)command;
-        repositoryService.persist(commandJdo);
-        return true;
-    }
-
-
-    /**
-     * Not API, also used by {@link CommandServiceJdoRepository}.
-     */
-    CommandJdo asUserInitiatedCommandJdo(final Command command) {
-        if(!(command instanceof CommandJdo)) {
-            // ought not to be the case, since this service created the object in the #create() method
-            return null;
-        }
-        if(command.getExecuteIn() != CommandExecuteIn.FOREGROUND) {
-            return null;
-        } 
-        final CommandJdo commandJdo = (CommandJdo) command;
-        return commandJdo.shouldPersist()? commandJdo: null;
-    }
-
-
-
-    @Inject
-    RepositoryService repositoryService;
-
-    @Inject
-    CommandServiceJdoRepository commandServiceJdoRepository;
-
-    @Inject
-    FactoryService factoryService;
-
-}
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/ReplayState.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/ReplayState.java
index 93dd52f..e4ebdb6 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/ReplayState.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/ReplayState.java
@@ -1,9 +1,43 @@
+/*
+ *  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.extensions.commandlog.impl.jdo;
 
 public enum ReplayState {
+    /**
+     * As used on primary system.
+     */
+    UNDEFINED,
+    /**
+     * For use on secondary system, indicates that the command has not yet been replayed.
+     */
     PENDING,
+    /**
+     * For use on secondary system, indicates that the command has been replayed ok
+     */
     OK,
+    /**
+     * For use on secondary system, indicates that the command has been replayed but encountered an error
+     */
     FAILED,
+    /**
+     * For use on secondary system, indicates that the command should not be replayed.
+     */
     EXCLUDED,
     ;
 
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/HasUniqueId_command.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/HasUniqueId_command.java
index 8deda59..3766317 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/HasUniqueId_command.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/HasUniqueId_command.java
@@ -12,7 +12,7 @@ import org.apache.isis.applib.services.command.Command;
 
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdoRepository;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 
 
 /**
@@ -53,9 +53,10 @@ public class HasUniqueId_command {
     private CommandJdo findCommand() {
         final UUID transactionId = hasUniqueId.getUniqueId();
         return commandServiceRepository
-                .findByTransactionId(transactionId)
+                .findByUniqueId(transactionId)
                 .orElse(null);
     }
 
-    @Inject CommandServiceJdoRepository commandServiceRepository;
+    @Inject
+    CommandJdoRepository commandServiceRepository;
 }
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/HasUsername_recentCommandsByUser.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/HasUsername_recentCommandsByUser.java
index adacb08..a94f9a8 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/HasUsername_recentCommandsByUser.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/HasUsername_recentCommandsByUser.java
@@ -11,7 +11,7 @@ import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.services.HasUsername;
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdoRepository;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 
 
 @Collection(
@@ -41,5 +41,6 @@ public class HasUsername_recentCommandsByUser {
         return hasUsername.getUsername() == null;
     }
 
-    @Inject CommandServiceJdoRepository commandServiceRepository;
+    @Inject
+    CommandJdoRepository commandServiceRepository;
 }
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/Object_recentCommands.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/Object_recentCommands.java
index 2be947a..bd8af7d 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/Object_recentCommands.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/Object_recentCommands.java
@@ -14,7 +14,7 @@ import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdoRepository;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 
 /**
  * This mixin contributes a <tt>recentCommands</tt> action to any domain object
@@ -53,7 +53,7 @@ public class Object_recentCommands {
     }
 
     @Inject
-    CommandServiceJdoRepository commandServiceRepository;
+    CommandJdoRepository commandServiceRepository;
     @Inject BookmarkService bookmarkService;
 
 }
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/T_backgroundCommands.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/T_backgroundCommands.java
index e997ab1..8e48b3e 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/T_backgroundCommands.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/mixins/T_backgroundCommands.java
@@ -11,7 +11,7 @@ import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.services.queryresultscache.QueryResultsCache;
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdoRepository;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 
 @Collection(
     domainEvent = T_backgroundCommands.CollectionDomainEvent.class
@@ -35,13 +35,14 @@ public abstract class T_backgroundCommands<T> {
     private List<CommandJdo> findRecentBackground() {
         final Bookmark bookmark = bookmarkService.bookmarkFor(domainObject);
         return queryResultsCache.execute(
-                () -> commandServiceJdoRepository.findRecentBackgroundByTarget(bookmark)
+                () -> commandJdoRepository.findRecentBackgroundByTarget(bookmark)
                 , T_backgroundCommands.class
                 , "findRecentBackground"
                 , domainObject);
     }
 
-    @Inject CommandServiceJdoRepository commandServiceJdoRepository;
+    @Inject
+    CommandJdoRepository commandJdoRepository;
     @Inject BookmarkService bookmarkService;
     @Inject QueryResultsCache queryResultsCache;
 
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/ui/CommandServiceMenu.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/ui/CommandServiceMenu.java
index f03d94b..685e784 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/ui/CommandServiceMenu.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/ui/CommandServiceMenu.java
@@ -26,7 +26,7 @@ import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdoRepository;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 
 @DomainService(
     nature = NatureOfService.VIEW,
@@ -94,14 +94,15 @@ public class CommandServiceMenu {
     public CommandJdo findCommandById(
             @ParameterLayout(named="Transaction Id")
             final UUID transactionId) {
-        return commandServiceRepository.findByTransactionId(transactionId).orElse(null);
+        return commandServiceRepository.findByUniqueId(transactionId).orElse(null);
     }
     public boolean hideFindCommandById() {
         return commandServiceRepository == null;
     }
 
 
-    @Inject CommandServiceJdoRepository commandServiceRepository;
+    @Inject
+    CommandJdoRepository commandServiceRepository;
     @Inject ClockService clockService;
 }
 
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserExceptionStr.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserExceptionStr.java
index e1571a0..1d98c15 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserExceptionStr.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserExceptionStr.java
@@ -4,7 +4,6 @@ import com.google.common.base.Objects;
 
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.CommandWithDto;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserNumberBackgroundCommands.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserNumberBackgroundCommands.java
index aaedd95..565d784 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserNumberBackgroundCommands.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserNumberBackgroundCommands.java
@@ -11,7 +11,7 @@ import org.apache.isis.applib.util.schema.CommandDtoUtils;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdoRepository;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 
 @DomainService()
 public class CommandReplayAnalyserNumberBackgroundCommands
@@ -37,7 +37,7 @@ public class CommandReplayAnalyserNumberBackgroundCommands
             final CommandJdo commandJdo = (CommandJdo) command;
 
             final List<CommandJdo> backgroundCommands =
-                    commandServiceJdoRepository.findBackgroundCommandsByParent(commandJdo);
+                    commandJdoRepository.findBackgroundCommandsByParent(commandJdo);
 
             CommandDtoUtils.setUserData(commandDto,
                     USERDATA_KEY_NUMBER_BACKGROUND_COMMANDS, ""+backgroundCommands.size());
@@ -73,7 +73,7 @@ public class CommandReplayAnalyserNumberBackgroundCommands
 
         final CommandJdo commandJdo = (CommandJdo) command;
         final List<CommandJdo> backgroundCommands =
-                commandServiceJdoRepository.findBackgroundCommandsByParent(commandJdo);
+                commandJdoRepository.findBackgroundCommandsByParent(commandJdo);
 
         final int slaveNumBackgroundCommands = backgroundCommands.size();
         if (masterNumBackgroundCommands == slaveNumBackgroundCommands) {
@@ -84,6 +84,7 @@ public class CommandReplayAnalyserNumberBackgroundCommands
                 masterNumBackgroundCommands, slaveNumBackgroundCommands);
     }
 
-    @Inject CommandServiceJdoRepository commandServiceJdoRepository;
+    @Inject
+    CommandJdoRepository commandJdoRepository;
 
 }
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserResultStr.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserResultStr.java
index 1c4a01c..7aa5177 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserResultStr.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalyserResultStr.java
@@ -4,7 +4,6 @@ import com.google.common.base.Objects;
 
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.CommandWithDto;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService.java
index b5317c0..ab1936e 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/analysis/CommandReplayAnalysisService.java
@@ -8,7 +8,6 @@ import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
 import org.apache.isis.extensions.commandlog.impl.jdo.ReplayState;
-import org.apache.isis.extensions.commandreplay.impl.analysis.CommandReplayAnalyser;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
 import lombok.extern.log4j.Log4j2;
@@ -34,7 +33,7 @@ public class CommandReplayAnalysisService {
     }
 
     private String analyseReplay(final CommandJdo commandJdo) {
-        final CommandDto dto = commandJdo.asDto();
+        final CommandDto dto = commandJdo.getCommandDto();
 
         for (final CommandReplayAnalyser analyser : analysers) {
             try {
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/CommandExecutorServiceWithTime.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/CommandExecutorServiceWithTime.java
index 0c2e724..59abc45 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/CommandExecutorServiceWithTime.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/CommandExecutorServiceWithTime.java
@@ -1,4 +1,4 @@
-/**
+/*
  *  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.
@@ -26,7 +26,6 @@ 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.CommandExecutorService;
-import org.apache.isis.applib.services.command.CommandWithDto;
 import org.apache.isis.extensions.commandreplay.impl.clock.TickingClockService;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
@@ -57,10 +56,10 @@ public class CommandExecutorServiceWithTime implements CommandExecutorService {
     }
 
     @Override
-    public void executeCommand(final SudoPolicy sudoPolicy, final CommandWithDto commandWithDto) {
-        final Runnable executeCommand = () -> delegate.executeCommand(sudoPolicy, commandWithDto);
+    public void executeCommand(final SudoPolicy sudoPolicy, final Command command) {
+        final Runnable executeCommand = () -> delegate.executeCommand(sudoPolicy, command);
         if(tickingClockService.isInitialized()) {
-            final Timestamp timestamp = commandWithDto.getTimestamp();
+            final Timestamp timestamp = command.getTimestamp();
             tickingClockService.at(timestamp, executeCommand);
         } else {
             executeCommand.run();
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/ReplayableCommandExecution.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/ReplayableCommandExecution.java
index 700a639..5da0059 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/ReplayableCommandExecution.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/executor/ReplayableCommandExecution.java
@@ -18,7 +18,7 @@ import org.apache.isis.extensions.commandreplay.impl.util.Holder;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdoRepository;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 
 import lombok.extern.log4j.Log4j2;
 
@@ -57,7 +57,7 @@ public class ReplayableCommandExecution
                 // first time through the loop we need to find the HWM command
                 // (subsequent iterations we use the command from before as the HWM)
                 log.debug("searching for hwm on slave ...");
-                hwmCommand = commandServiceJdoRepository.findReplayHwm();
+                hwmCommand = commandJdoRepository.findReplayHwm();
             }
 
             if(hwmCommand == null) {
@@ -67,7 +67,7 @@ public class ReplayableCommandExecution
             }
 
             log.debug("current hwm transactionId = {} {} {} {}",
-                    hwmCommand.getTransactionId(), hwmCommand.getTimestamp(),
+                    hwmCommand.getUniqueId(), hwmCommand.getTimestamp(),
                     hwmCommand.getExecuteIn(), hwmCommand.getMemberIdentifier());
 
 
@@ -89,7 +89,7 @@ public class ReplayableCommandExecution
                     // check that the current HWM was replayed successfully, otherwise break out
                     //
                     if(hwmCommand.getReplayState().isFailed()) {
-                        log.info("Command xactnId={} hit replay error", hwmCommand.getTransactionId());
+                        log.info("Command xactnId={} hit replay error", hwmCommand.getUniqueId());
                         return;
                     }
                     fetchNext = true;
@@ -99,7 +99,7 @@ public class ReplayableCommandExecution
             default:
                 log.error(
                         "HWM command xactnId={} should be either FOREGROUND or REPLAYABLE but is instead {}; aborting",
-                        hwmCommand.getTransactionId(), hwmCommand.getExecuteIn());
+                        hwmCommand.getUniqueId(), hwmCommand.getExecuteIn());
                 return;
             }
 
@@ -114,10 +114,10 @@ public class ReplayableCommandExecution
                 }
 
                 hwmCommand = transactionService.executeWithinTransaction(
-                        () -> commandServiceJdoRepository.saveForReplay(commandDto));
+                        () -> commandJdoRepository.saveForReplay(commandDto));
             }
 
-            log.info("next HWM transactionId = {} {} {} {}", hwmCommand.getTransactionId());
+            log.info("next HWM transactionId = {} {} {} {}", hwmCommand.getUniqueId());
 
 
 
@@ -133,7 +133,7 @@ public class ReplayableCommandExecution
             final CommandJdo parent = hwmCommand;
             final List<CommandJdo> backgroundCommands =
                     transactionService.executeWithinTransaction(
-                            () -> commandServiceJdoRepository.findBackgroundCommandsByParent(parent));
+                            () -> commandJdoRepository.findBackgroundCommandsByParent(parent));
             for (final CommandJdo backgroundCommand : backgroundCommands) {
                 execute(backgroundCommand, transactionService);
             }
@@ -169,7 +169,8 @@ public class ReplayableCommandExecution
     @Inject TransactionService transactionService;
     @Inject
     CommandFetcher commandFetcher;
-    @Inject CommandServiceJdoRepository commandServiceJdoRepository;
+    @Inject
+    CommandJdoRepository commandJdoRepository;
     @Inject
     CommandReplayAnalysisService analysisService;
     @Inject ReplayCommandExecutionController controller;
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_download.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_download.java
index 6c25cd1..6faef66 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_download.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_download.java
@@ -4,7 +4,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.MemberOrder;
 import org.apache.isis.applib.annotation.ParameterLayout;
 import org.apache.isis.applib.annotation.SemanticsOf;
@@ -38,7 +37,7 @@ public class CommandJdo_download {
     public Clob act(
             @ParameterLayout(named="Filename prefix")
             final String fileNamePrefix) {
-        return commandReplayOnMasterService.downloadCommandById(commandJdo.getTransactionId(), fileNamePrefix);
+        return commandReplayOnMasterService.downloadCommandById(commandJdo.getUniqueId(), fileNamePrefix);
     }
     public String default0Act() {
         return "command";
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_exclude.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_exclude.java
index 0c89af5..071f818 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_exclude.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_exclude.java
@@ -1,7 +1,6 @@
 package org.apache.isis.extensions.commandreplay.impl.mixins;
 
 import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.CommandPersistence;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayNext.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayNext.java
index e09d0b9..93f9a7a 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayNext.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayNext.java
@@ -5,13 +5,12 @@ import java.util.List;
 import javax.inject.Inject;
 
 import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.CommandPersistence;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.command.CommandExecutorService;
 import org.apache.isis.applib.services.message.MessageService;
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdoRepository;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 import org.apache.isis.extensions.commandreplay.impl.IsisModuleExtCommandReplayImpl;
 import org.apache.isis.extensions.commandreplay.impl.fetch.MasterConfiguration;
 import org.apache.isis.extensions.commandreplay.impl.StatusException;
@@ -38,7 +37,7 @@ public class CommandJdo_replayNext {
     public CommandJdo act() throws StatusException {
 
         // double check this is still the HWM
-        final CommandJdo replayHwm = commandServiceJdoRepository.findReplayHwm();
+        final CommandJdo replayHwm = commandJdoRepository.findReplayHwm();
         if(commandJdo != replayHwm) {
             messageService.informUser("HWM has changed");
             return replayHwm;
@@ -61,7 +60,7 @@ public class CommandJdo_replayNext {
         final CommandDto commandDto = commandFetcher.fetchCommand(this.commandJdo);
         return commandDto == null
                 ? null
-                : commandServiceJdoRepository.saveForReplay(commandDto);
+                : commandJdoRepository.saveForReplay(commandDto);
     }
 
     private void execute(final CommandJdo hwmCommand) {
@@ -70,14 +69,14 @@ public class CommandJdo_replayNext {
         commandExecutorService.executeCommand(CommandExecutorService.SudoPolicy.SWITCH, hwmCommand);
 
         // find background commands, and run them
-        final List<CommandJdo> backgroundCommands = commandServiceJdoRepository.findBackgroundCommandsByParent(hwmCommand);
+        final List<CommandJdo> backgroundCommands = commandJdoRepository.findBackgroundCommandsByParent(hwmCommand);
         for (final CommandJdo backgroundCommand : backgroundCommands) {
             commandExecutorService.executeCommand(CommandExecutorService.SudoPolicy.SWITCH, backgroundCommand);
         }
     }
 
     public String disableAct() {
-        final CommandJdo replayHwm = commandServiceJdoRepository.findReplayHwm();
+        final CommandJdo replayHwm = commandJdoRepository.findReplayHwm();
 
         if(commandJdo != replayHwm) {
             return "This action can only be performed against the 'HWM' command on the slave";
@@ -103,7 +102,7 @@ public class CommandJdo_replayNext {
 
 
     @Inject
-    CommandServiceJdoRepository commandServiceJdoRepository;
+    CommandJdoRepository commandJdoRepository;
     @Inject CommandFetcher commandFetcher;
     @Inject CommandExecutorService commandExecutorService;
     @Inject
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayQueue.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayQueue.java
index 2f4286d..924c861 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayQueue.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/mixins/CommandJdo_replayQueue.java
@@ -9,7 +9,7 @@ import org.apache.isis.applib.annotation.CollectionLayout;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.Mixin;
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdoRepository;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 import org.apache.isis.extensions.commandreplay.impl.IsisModuleExtCommandReplayImpl;
 import org.apache.isis.extensions.commandreplay.impl.fetch.MasterConfiguration;
 
@@ -32,7 +32,7 @@ public class CommandJdo_replayQueue {
 
     @MemberOrder(sequence = "100.100")
     public List<CommandJdo> coll() {
-        return commandServiceJdoRepository.findReplayedOnSlave();
+        return commandJdoRepository.findReplayedOnSlave();
     }
 
     public boolean hideColl() {
@@ -42,6 +42,6 @@ public class CommandJdo_replayQueue {
     @Inject
     MasterConfiguration masterConfiguration;
     @Inject
-    CommandServiceJdoRepository commandServiceJdoRepository;
+    CommandJdoRepository commandJdoRepository;
 
 }
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/quartz/RunBackgroundCommandsWithReplicationAndReplayJob.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/quartz/RunBackgroundCommandsWithReplicationAndReplayJob.java
index a68911f..034a3db 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/quartz/RunBackgroundCommandsWithReplicationAndReplayJob.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/quartz/RunBackgroundCommandsWithReplicationAndReplayJob.java
@@ -16,7 +16,6 @@ import org.apache.isis.core.runtime.iactn.template.AbstractIsisInteractionTempla
 import org.apache.isis.core.security.authentication.AuthenticationSession;
 import org.apache.isis.core.security.authentication.standard.SimpleSession;
 
-import org.apache.isis.extensions.commandlog.impl.background.BackgroundCommandExecutionFromBackgroundCommandServiceJdo;
 import org.apache.isis.extensions.commandreplay.impl.clock.TickingClockService;
 import org.apache.isis.extensions.commandreplay.impl.util.Holder;
 import org.apache.isis.extensions.commandreplay.impl.executor.ReplayableCommandExecution;
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnMasterService.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnMasterService.java
index ea55bc2..c3bb759 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnMasterService.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnMasterService.java
@@ -21,7 +21,7 @@ import org.apache.isis.applib.services.jaxb.JaxbService;
 import org.apache.isis.applib.services.message.MessageService;
 import org.apache.isis.applib.value.Clob;
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdoRepository;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 import org.apache.isis.extensions.commandreplay.impl.IsisModuleExtCommandReplayImpl;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.cmd.v2.CommandsDto;
@@ -158,7 +158,7 @@ public class CommandReplayOnMasterService {
             @ParameterLayout(named="Filename prefix")
             final String fileNamePrefix) {
 
-        return commandServiceRepository.findByTransactionId(transactionId)
+        return commandServiceRepository.findByUniqueId(transactionId)
                 .map(commandJdo -> {
 
                     final CommandDto commandDto =
@@ -180,7 +180,8 @@ public class CommandReplayOnMasterService {
     }
 
 
-    @Inject CommandServiceJdoRepository commandServiceRepository;
+    @Inject
+    CommandJdoRepository commandServiceRepository;
     @Inject JaxbService jaxbService;
     @Inject MessageService messageService;
     @Inject ContentMappingServiceForCommandsDto contentMappingServiceForCommandsDto;
diff --git a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnSlaveService.java b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnSlaveService.java
index e30e323..cbd037c 100644
--- a/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnSlaveService.java
+++ b/extensions/core/command-replay/impl/src/main/java/org/apache/isis/extensions/commandreplay/impl/ui/CommandReplayOnSlaveService.java
@@ -7,7 +7,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.CommandReification;
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.DomainServiceLayout;
 import org.apache.isis.applib.annotation.MemberOrder;
@@ -16,7 +15,7 @@ import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.services.jaxb.JaxbService;
 import org.apache.isis.applib.value.Clob;
 import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdo;
-import org.apache.isis.extensions.commandlog.impl.jdo.CommandServiceJdoRepository;
+import org.apache.isis.extensions.commandlog.impl.jdo.CommandJdoRepository;
 import org.apache.isis.extensions.commandreplay.impl.IsisModuleExtCommandReplayImpl;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.cmd.v2.CommandsDto;
@@ -43,7 +42,7 @@ public class CommandReplayOnSlaveService {
     @ActionLayout(cssClassFa = "fa-bath")
     @MemberOrder(sequence="60.1")
     public CommandJdo findReplayHwmOnSlave() {
-        return commandServiceJdoRepository.findReplayHwm();
+        return commandJdoRepository.findReplayHwm();
     }
 
 
@@ -70,14 +69,14 @@ public class CommandReplayOnSlaveService {
         }
 
         for (final CommandDto commandDto : commandDtoList) {
-            commandServiceJdoRepository.saveForReplay(commandDto);
+            commandJdoRepository.saveForReplay(commandDto);
         }
     }
 
 
 
     @Inject
-    CommandServiceJdoRepository commandServiceJdoRepository;
+    CommandJdoRepository commandJdoRepository;
     @Inject JaxbService jaxbService;
 
 }
diff --git a/extensions/core/quartz/impl/src/main/java/org/apache/isis/extensions/quartz/jobs/RunBackgroundCommandsJob.java b/extensions/core/quartz/impl/src/main/java/org/apache/isis/extensions/quartz/jobs/RunBackgroundCommandsJob.java
index c0391b8..75712e4 100644
--- a/extensions/core/quartz/impl/src/main/java/org/apache/isis/extensions/quartz/jobs/RunBackgroundCommandsJob.java
+++ b/extensions/core/quartz/impl/src/main/java/org/apache/isis/extensions/quartz/jobs/RunBackgroundCommandsJob.java
@@ -3,8 +3,6 @@ package org.apache.isis.extensions.quartz.jobs;
 
 import javax.inject.Inject;
 
-import com.google.common.base.Splitter;
-
 import org.quartz.Job;
 import org.quartz.JobExecutionContext;
 
@@ -12,8 +10,6 @@ import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.security.authentication.AuthenticationSession;
 import org.apache.isis.core.security.authentication.standard.SimpleSession;
 
-import org.apache.isis.extensions.commandlog.impl.background.BackgroundCommandExecutionFromBackgroundCommandServiceJdo;
-
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisBookmarkConverter.java
similarity index 70%
copy from persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
copy to persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisBookmarkConverter.java
index 3daffaa..838a998 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisBookmarkConverter.java
@@ -16,27 +16,29 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters;
+package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.applib;
 
 import org.datanucleus.store.types.converters.TypeConverter;
 
-import org.apache.isis.applib.value.Markup;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.util.schema.ChangesDtoUtils;
+import org.apache.isis.schema.chg.v2.ChangesDto;
 
-public class IsisMarkupConverter implements TypeConverter<Markup, String>{
+public class IsisBookmarkConverter implements TypeConverter<Bookmark, String>{
 
     private static final long serialVersionUID = 1L;
 
     @Override
-    public String toDatastoreType(final Markup memberValue) {
+    public String toDatastoreType(final Bookmark memberValue) {
         return memberValue != null
-                ? memberValue.asHtml()
+                ? memberValue.toString()
                         : null;
     }
 
     @Override
-    public Markup toMemberType(final String datastoreValue) {
+    public Bookmark toMemberType(final String datastoreValue) {
         return datastoreValue != null
-                ? new Markup(datastoreValue)
+                ? Bookmark.parse(datastoreValue)
                         : null;
     }
 
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisLocalResourcePathConverter.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisLocalResourcePathConverter.java
similarity index 98%
rename from persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisLocalResourcePathConverter.java
rename to persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisLocalResourcePathConverter.java
index 8663815..57d593a 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisLocalResourcePathConverter.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisLocalResourcePathConverter.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters;
+package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.applib;
 
 import org.datanucleus.store.types.converters.TypeConverter;
 
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisMarkupConverter.java
similarity index 98%
copy from persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
copy to persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisMarkupConverter.java
index 3daffaa..ba910ca 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisMarkupConverter.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters;
+package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.applib;
 
 import org.datanucleus.store.types.converters.TypeConverter;
 
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisPasswordConverter.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisPasswordConverter.java
similarity index 98%
copy from persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisPasswordConverter.java
copy to persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisPasswordConverter.java
index 6fd4969..ee7dc8c 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisPasswordConverter.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/applib/IsisPasswordConverter.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters;
+package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.applib;
 
 import org.datanucleus.store.types.converters.TypeConverter;
 
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/schema/v2/IsisChangesDtoConverter.java
similarity index 72%
copy from persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
copy to persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/schema/v2/IsisChangesDtoConverter.java
index 3daffaa..a60e018 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/schema/v2/IsisChangesDtoConverter.java
@@ -16,27 +16,28 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters;
+package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.schema.v2;
 
 import org.datanucleus.store.types.converters.TypeConverter;
 
-import org.apache.isis.applib.value.Markup;
+import org.apache.isis.applib.util.schema.ChangesDtoUtils;
+import org.apache.isis.schema.chg.v2.ChangesDto;
 
-public class IsisMarkupConverter implements TypeConverter<Markup, String>{
+public class IsisChangesDtoConverter implements TypeConverter<ChangesDto, String>{
 
     private static final long serialVersionUID = 1L;
 
     @Override
-    public String toDatastoreType(final Markup memberValue) {
+    public String toDatastoreType(final ChangesDto memberValue) {
         return memberValue != null
-                ? memberValue.asHtml()
+                ? ChangesDtoUtils.toXml(memberValue)
                         : null;
     }
 
     @Override
-    public Markup toMemberType(final String datastoreValue) {
+    public ChangesDto toMemberType(final String datastoreValue) {
         return datastoreValue != null
-                ? new Markup(datastoreValue)
+                ? ChangesDtoUtils.fromXml(datastoreValue)
                         : null;
     }
 
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisPasswordConverter.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/schema/v2/IsisCommandDtoConverter.java
similarity index 67%
rename from persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisPasswordConverter.java
rename to persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/schema/v2/IsisCommandDtoConverter.java
index 6fd4969..d0d304f 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisPasswordConverter.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/schema/v2/IsisCommandDtoConverter.java
@@ -16,27 +16,30 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters;
+package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.schema.v2;
 
 import org.datanucleus.store.types.converters.TypeConverter;
 
-import org.apache.isis.applib.value.Password;
+import org.apache.isis.applib.util.schema.CommandDtoUtils;
+import org.apache.isis.applib.util.schema.InteractionDtoUtils;
+import org.apache.isis.schema.cmd.v2.CommandDto;
+import org.apache.isis.schema.ixn.v2.InteractionDto;
 
-public class IsisPasswordConverter implements TypeConverter<Password, String>{
+public class IsisCommandDtoConverter implements TypeConverter<CommandDto, String>{
 
     private static final long serialVersionUID = 1L;
 
     @Override
-    public String toDatastoreType(final Password memberValue) {
+    public String toDatastoreType(final CommandDto memberValue) {
         return memberValue != null
-                ? memberValue.getPassword()
+                ? CommandDtoUtils.toXml(memberValue)
                         : null;
     }
 
     @Override
-    public Password toMemberType(final String datastoreValue) {
+    public CommandDto toMemberType(final String datastoreValue) {
         return datastoreValue != null
-                ? new Password(datastoreValue)
+                ? CommandDtoUtils.fromXml(datastoreValue)
                         : null;
     }
 
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/schema/v2/IsisInteractionDtoConverter.java
similarity index 71%
copy from persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
copy to persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/schema/v2/IsisInteractionDtoConverter.java
index 3daffaa..1071ed0 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/schema/v2/IsisInteractionDtoConverter.java
@@ -16,27 +16,29 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters;
+package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.schema.v2;
 
 import org.datanucleus.store.types.converters.TypeConverter;
 
+import org.apache.isis.applib.util.schema.InteractionDtoUtils;
 import org.apache.isis.applib.value.Markup;
+import org.apache.isis.schema.ixn.v2.InteractionDto;
 
-public class IsisMarkupConverter implements TypeConverter<Markup, String>{
+public class IsisInteractionDtoConverter implements TypeConverter<InteractionDto, String>{
 
     private static final long serialVersionUID = 1L;
 
     @Override
-    public String toDatastoreType(final Markup memberValue) {
+    public String toDatastoreType(final InteractionDto memberValue) {
         return memberValue != null
-                ? memberValue.asHtml()
+                ? InteractionDtoUtils.toXml(memberValue)
                         : null;
     }
 
     @Override
-    public Markup toMemberType(final String datastoreValue) {
+    public InteractionDto toMemberType(final String datastoreValue) {
         return datastoreValue != null
-                ? new Markup(datastoreValue)
+                ? InteractionDtoUtils.fromXml(datastoreValue)
                         : null;
     }
 
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/schema/v2/IsisOidDtoConverter.java
similarity index 64%
copy from persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
copy to persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/schema/v2/IsisOidDtoConverter.java
index 3daffaa..ad3980c 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/schema/v2/IsisOidDtoConverter.java
@@ -16,28 +16,33 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters;
+package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.schema.v2;
 
 import org.datanucleus.store.types.converters.TypeConverter;
 
-import org.apache.isis.applib.value.Markup;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.util.schema.ChangesDtoUtils;
+import org.apache.isis.schema.chg.v2.ChangesDto;
+import org.apache.isis.schema.common.v2.OidDto;
 
-public class IsisMarkupConverter implements TypeConverter<Markup, String>{
+public class IsisOidDtoConverter implements TypeConverter<OidDto, String>{
 
     private static final long serialVersionUID = 1L;
 
     @Override
-    public String toDatastoreType(final Markup memberValue) {
+    public String toDatastoreType(final OidDto memberValue) {
         return memberValue != null
-                ? memberValue.asHtml()
+                ? Bookmark.from(memberValue).toString()
                         : null;
     }
 
     @Override
-    public Markup toMemberType(final String datastoreValue) {
+    public OidDto toMemberType(final String datastoreValue) {
         return datastoreValue != null
-                ? new Markup(datastoreValue)
-                        : null;
+                ? Bookmark.parse(datastoreValue)
+                    .map(Bookmark::toOidDto)
+                    .orElse(null)
+                : null;
     }
 
 }
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuemappings/ByteArrayBlobRdbmsMapping.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuemappings/applib/ByteArrayBlobRdbmsMapping.java
similarity index 98%
rename from persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuemappings/ByteArrayBlobRdbmsMapping.java
rename to persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuemappings/applib/ByteArrayBlobRdbmsMapping.java
index 993e782..5165abb 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuemappings/ByteArrayBlobRdbmsMapping.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuemappings/applib/ByteArrayBlobRdbmsMapping.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.valuemappings;
+package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.valuemappings.applib;
 
 import org.datanucleus.store.rdbms.RDBMSStoreManager;
 import org.datanucleus.store.rdbms.mapping.column.BlobColumnMapping;
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuetypes/IsisBlobMapping.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuetypes/applib/IsisBlobMapping.java
similarity index 99%
rename from persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuetypes/IsisBlobMapping.java
rename to persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuetypes/applib/IsisBlobMapping.java
index f3fbda2..55a3d5e 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuetypes/IsisBlobMapping.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuetypes/applib/IsisBlobMapping.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.valuetypes;
+package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.valuetypes.applib;
 
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuetypes/IsisClobMapping.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuetypes/applib/IsisClobMapping.java
similarity index 99%
rename from persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuetypes/IsisClobMapping.java
rename to persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuetypes/applib/IsisClobMapping.java
index c5f5a4b..c8e6be6 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuetypes/IsisClobMapping.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/valuetypes/applib/IsisClobMapping.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.valuetypes;
+package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.valuetypes.applib;
 
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/PersistenceSession5.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/PersistenceSession5.java
index 1b307c3..10c8dca 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/PersistenceSession5.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/PersistenceSession5.java
@@ -75,7 +75,6 @@ import org.apache.isis.core.metamodel.facets.object.callbacks.UpdatingCallbackFa
 import org.apache.isis.core.metamodel.facets.object.callbacks.UpdatingLifecycleEventFacet;
 import org.apache.isis.core.metamodel.services.container.query.QueryCardinality;
 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;
 import org.apache.isis.persistence.jdo.applib.exceptions.NotPersistableException;
 import org.apache.isis.persistence.jdo.applib.exceptions.UnsupportedFindException;
@@ -176,7 +175,7 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
         final String userName = userService.getUser().getName();
 
         command.internal().setTimestamp(timestamp);
-        command.internal().setUser(userName);
+        command.internal().setUsername(userName);
 
         interaction.setUniqueId(command.getUniqueId());
 
diff --git a/persistence/jdo/datanucleus-5/src/main/resources/plugin.xml b/persistence/jdo/datanucleus-5/src/main/resources/plugin.xml
index e3e5b74..bb5b2e9 100644
--- a/persistence/jdo/datanucleus-5/src/main/resources/plugin.xml
+++ b/persistence/jdo/datanucleus-5/src/main/resources/plugin.xml
@@ -28,10 +28,10 @@
     <extension point="org.datanucleus.store.rdbms.java_mapping">
         <mapping
             java-type="org.apache.isis.applib.value.Blob"
-            mapping-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.valuetypes.IsisBlobMapping"/>
+            mapping-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.valuetypes.applib.IsisBlobMapping"/>
         <mapping
             java-type="org.apache.isis.applib.value.Clob"
-            mapping-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.valuetypes.IsisClobMapping"/>
+            mapping-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.valuetypes.applib.IsisClobMapping"/>
         
         <!-- TODO[2249] deprecated
         <mapping
@@ -50,14 +50,14 @@
                 jdbc-type="BLOB"
                 sql-type="BLOB"
                 default="true"
-                column-mapping-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.valuemappings.ByteArrayBlobRdbmsMapping">
+                column-mapping-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.valuemappings.applib.ByteArrayBlobRdbmsMapping">
         </mapping>
         <mapping
                 java-type="[Ljava.lang.Byte;"
                 jdbc-type="BLOB"
                 sql-type="BLOB"
                 default="true"
-                column-mapping-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.valuemappings.ByteArrayBlobRdbmsMapping">
+                column-mapping-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.valuemappings.applib.ByteArrayBlobRdbmsMapping">
         </mapping>
     </extension>
 
@@ -85,6 +85,41 @@
                 converter-name="isis.localresourcepath-string" />
     </extension>
 
+    <extension point="org.datanucleus.java_type">
+        <java-type
+                name="org.apache.isis.applib.services.bookmark.Bookmark"
+                dfg="true"
+                converter-name="isis.bookmark-string" />
+    </extension>
+
+    <extension point="org.datanucleus.java_type">
+        <java-type
+                name="org.apache.isis.schema.chg.v2.ChangesDto"
+                dfg="true"
+                converter-name="isis.changesdtov2-string" />
+    </extension>
+
+    <extension point="org.datanucleus.java_type">
+        <java-type
+                name="org.apache.isis.schema.common.v2.OidDto"
+                dfg="true"
+                converter-name="isis.oiddtov2-string" />
+    </extension>
+
+    <extension point="org.datanucleus.java_type">
+        <java-type
+                name="org.apache.isis.schema.cmd.v2.CommandDto"
+                dfg="true"
+                converter-name="isis.commanddtov2-string" />
+    </extension>
+
+    <extension point="org.datanucleus.java_type">
+        <java-type
+                name="org.apache.isis.schema.ixn.v2.InteractionDto"
+                dfg="true"
+                converter-name="isis.interactiondtov2-string" />
+    </extension>
+
     <!--
     http://www.datanucleus.org/extensions/type_converter.html
     -->
@@ -93,30 +128,63 @@
                 name="isis.password-string"
                 member-type="org.apache.isis.applib.value.Password"
                 datastore-type="java.lang.String"
-                converter-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.IsisPasswordConverter"/>
+                converter-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.applib.IsisPasswordConverter"/>
     </extension>
 
-    <!--
-    http://www.datanucleus.org/extensions/type_converter.html
-    -->
     <extension point="org.datanucleus.type_converter">
         <type-converter
                 name="isis.markup-string"
                 member-type="org.apache.isis.applib.value.Markup"
                 datastore-type="java.lang.String"
-                converter-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.IsisMarkupConverter"/>
+                converter-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.applib.IsisMarkupConverter"/>
     </extension>
 
-
-    <!--
-    http://www.datanucleus.org/extensions/type_converter.html
-    -->
     <extension point="org.datanucleus.type_converter">
         <type-converter
                 name="isis.localresourcepath-string"
                 member-type="org.apache.isis.applib.value.LocalResourcePath"
                 datastore-type="java.lang.String"
-                converter-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.IsisLocalResourcePathConverter"/>
+                converter-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.applib.IsisLocalResourcePathConverter"/>
+    </extension>
+
+    <extension point="org.datanucleus.type_converter">
+        <type-converter
+                name="isis.bookmark-string"
+                member-type="org.apache.isis.applib.services.bookmark.Bookmark"
+                datastore-type="java.lang.String"
+                converter-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.applib.IsisBookmarkConverter"/>
+    </extension>
+
+    <extension point="org.datanucleus.type_converter">
+        <type-converter
+                name="isis.changesdtov2-string"
+                member-type="org.apache.isis.schema.chg.v2.ChangesDto"
+                datastore-type="java.lang.String"
+                converter-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.schema.v2.IsisChangesDtoConverter"/>
+    </extension>
+
+    <extension point="org.datanucleus.type_converter">
+        <type-converter
+                name="isis.oiddtov2-string"
+                member-type="org.apache.isis.schema.common.v2.OidDto"
+                datastore-type="java.lang.String"
+                converter-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.schema.v2.IsisOidDtoConverter"/>
+    </extension>
+
+    <extension point="org.datanucleus.type_converter">
+        <type-converter
+                name="isis.commanddtov2-string"
+                member-type="org.apache.isis.schema.cmd.v2.CommandDto"
+                datastore-type="java.lang.String"
+                converter-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.schema.v2.IsisCommandDtoConverter"/>
+    </extension>
+
+    <extension point="org.datanucleus.type_converter">
+        <type-converter
+                name="isis.interactiondtov2-string"
+                member-type="org.apache.isis.schema.ixn.v2.InteractionDto"
+                datastore-type="java.lang.String"
+                converter-class="org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters.schema.v2.IsisInteractionDtoConverter"/>
     </extension>
 
 </plugin>
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/background/package-info.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/bookmark/BookmarkPanel.java
similarity index 56%
rename from api/applib/src/main/java/org/apache/isis/applib/services/background/package-info.java
rename to viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/bookmark/BookmarkPanel.java
index f63812d..a9611d3 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/background/package-info.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/bookmark/BookmarkPanel.java
@@ -17,11 +17,28 @@
  *  under the License.
  */
 
+package org.apache.isis.viewer.wicket.ui.components.scalars.bookmark;
+
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldParseableAbstract;
+
 /**
- * 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
- *
- *
+ * Panel for rendering scalars of type {@link Bookmark}.
  */
-package org.apache.isis.applib.services.background;
\ No newline at end of file
+public class BookmarkPanel extends ScalarPanelTextFieldParseableAbstract {
+
+    private static final long serialVersionUID = 1L;
+
+
+    public BookmarkPanel(final String id, final ScalarModel scalarModel) {
+        super(id, scalarModel);
+    }
+
+    @Override
+    protected String getScalarPanelType() {
+        return "bookmarkPanel";
+    }
+
+
+
+}
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/bookmark/BookmarkPanelFactory.java
similarity index 53%
copy from persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
copy to viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/bookmark/BookmarkPanelFactory.java
index 3daffaa..c9e3f80 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/bookmark/BookmarkPanelFactory.java
@@ -16,28 +16,27 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters;
 
-import org.datanucleus.store.types.converters.TypeConverter;
+package org.apache.isis.viewer.wicket.ui.components.scalars.bookmark;
 
-import org.apache.isis.applib.value.Markup;
+import org.apache.wicket.Component;
 
-public class IsisMarkupConverter implements TypeConverter<Markup, String>{
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.core.metamodel.facets.objectvalue.multiline.MultiLineFacet;
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ComponentFactoryScalarAbstract;
+import org.apache.isis.viewer.wicket.ui.components.scalars.string.MultiLineStringPanel;
+
+public class BookmarkPanelFactory extends ComponentFactoryScalarAbstract {
 
     private static final long serialVersionUID = 1L;
 
-    @Override
-    public String toDatastoreType(final Markup memberValue) {
-        return memberValue != null
-                ? memberValue.asHtml()
-                        : null;
+    public BookmarkPanelFactory() {
+        super(BookmarkPanel.class, Bookmark.class);
     }
 
     @Override
-    public Markup toMemberType(final String datastoreValue) {
-        return datastoreValue != null
-                ? new Markup(datastoreValue)
-                        : null;
+    public Component createComponent(final String id, final ScalarModel scalarModel) {
+        return new BookmarkPanel(id, scalarModel);
     }
-
 }
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/oiddto/OidDtoPanel.java
similarity index 59%
copy from persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
copy to viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/oiddto/OidDtoPanel.java
index 3daffaa..0ecdf92 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/oiddto/OidDtoPanel.java
@@ -16,28 +16,29 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters;
 
-import org.datanucleus.store.types.converters.TypeConverter;
+package org.apache.isis.viewer.wicket.ui.components.scalars.oiddto;
 
-import org.apache.isis.applib.value.Markup;
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelTextFieldParseableAbstract;
 
-public class IsisMarkupConverter implements TypeConverter<Markup, String>{
+/**
+ * Panel for rendering scalars of type {@link org.apache.isis.schema.common.v2.OidDto}.
+ */
+public class OidDtoPanel extends ScalarPanelTextFieldParseableAbstract {
 
     private static final long serialVersionUID = 1L;
 
-    @Override
-    public String toDatastoreType(final Markup memberValue) {
-        return memberValue != null
-                ? memberValue.asHtml()
-                        : null;
+
+    public OidDtoPanel(final String id, final ScalarModel scalarModel) {
+        super(id, scalarModel);
     }
 
     @Override
-    public Markup toMemberType(final String datastoreValue) {
-        return datastoreValue != null
-                ? new Markup(datastoreValue)
-                        : null;
+    protected String getScalarPanelType() {
+        return "oidDtoPanel";
     }
 
+
+
 }
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/oiddto/OidDtoPanelFactory.java
similarity index 59%
rename from persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
rename to viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/oiddto/OidDtoPanelFactory.java
index 3daffaa..4d69b5d 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/datanucleus/typeconverters/IsisMarkupConverter.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/oiddto/OidDtoPanelFactory.java
@@ -16,28 +16,25 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.datanucleus5.datanucleus.typeconverters;
 
-import org.datanucleus.store.types.converters.TypeConverter;
+package org.apache.isis.viewer.wicket.ui.components.scalars.oiddto;
 
-import org.apache.isis.applib.value.Markup;
+import org.apache.wicket.Component;
 
-public class IsisMarkupConverter implements TypeConverter<Markup, String>{
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.ui.components.scalars.ComponentFactoryScalarAbstract;
+
+public class OidDtoPanelFactory extends ComponentFactoryScalarAbstract {
 
     private static final long serialVersionUID = 1L;
 
-    @Override
-    public String toDatastoreType(final Markup memberValue) {
-        return memberValue != null
-                ? memberValue.asHtml()
-                        : null;
+    public OidDtoPanelFactory() {
+        super(OidDtoPanel.class, Bookmark.class);
     }
 
     @Override
-    public Markup toMemberType(final String datastoreValue) {
-        return datastoreValue != null
-                ? new Markup(datastoreValue)
-                        : null;
+    public Component createComponent(final String id, final ScalarModel scalarModel) {
+        return new OidDtoPanel(id, scalarModel);
     }
-
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
index 413ab0d..fcb048b 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
@@ -123,12 +123,6 @@ implements FormExecutor {
                 return false;
             }
 
-            val commandContext = currentCommandContext().orElse(null);
-            if (commandContext != null) {
-                command = commandContext.getCommand();
-                command.internal().setExecutor(Command.Executor.USER);
-            }
-
 
             //
             // the following line will (attempt to) invoke the action, and will in turn either:
@@ -248,11 +242,7 @@ implements FormExecutor {
             // irrespective, capture error in the Command, and propagate
             if (command != null) {
                 
-                val stackTraceAsString = 
-                _Exceptions.streamStacktraceLines(ex, 1000)
-                .collect(Collectors.joining("\n"));
-                
-                command.internal().setException(stackTraceAsString);
+                command.internal().setException(ex);
                 
                 //XXX legacy of
                 //command.internal().setException(Throwables.getStackTraceAsString(ex));
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
index 0f126d9..0b303db 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
@@ -29,6 +29,7 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.core.commons.internal.base._NullSafe;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
 import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistrar;
@@ -54,6 +55,7 @@ import org.apache.isis.viewer.wicket.ui.components.footer.FooterPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.header.HeaderPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.property.PropertyEditFormPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.property.PropertyEditPanelFactory;
+import org.apache.isis.viewer.wicket.ui.components.scalars.bookmark.BookmarkPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisBlobPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisClobPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisPasswordPanelFactory;
@@ -70,6 +72,7 @@ import org.apache.isis.viewer.wicket.ui.components.scalars.jodatime.JodaDateTime
 import org.apache.isis.viewer.wicket.ui.components.scalars.jodatime.JodaLocalDatePanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.jodatime.JodaLocalDateTimePanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.markup.MarkupPanelFactories;
+import org.apache.isis.viewer.wicket.ui.components.scalars.oiddto.OidDtoPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.primitive.BooleanPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.primitive.BytePanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.scalars.primitive.CharacterPanelFactory;
@@ -228,6 +231,7 @@ public class ComponentFactoryRegistrarDefault implements ComponentFactoryRegistr
 
         componentFactories.add(new StringPanelFactory());
 
+
         // work-in-progress
         // componentFactories.add(new JavaAwtImagePanelFactory());
         componentFactories.add(new JavaUtilDatePanelFactory());
@@ -237,6 +241,9 @@ public class ComponentFactoryRegistrarDefault implements ComponentFactoryRegistr
 
         componentFactories.add(new IsisPasswordPanelFactory());
 
+        componentFactories.add(new BookmarkPanelFactory());
+        componentFactories.add(new OidDtoPanelFactory());
+
         componentFactories.add(new IsisBlobPanelFactory());
         componentFactories.add(new IsisClobPanelFactory());