You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by da...@apache.org on 2026/06/08 07:37:15 UTC

(causeway) 10/27: CAUSEWAY-4023: proposes preserving replay command DTOs

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

danhaywood pushed a commit to branch CAUSEWAY-4025
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit a496aec109435ebc2a12b21af2340010a7ebdbca
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Mon Jun 8 05:43:16 2026 +0100

    CAUSEWAY-4023: proposes preserving replay command DTOs
---
 .../.openspec.yaml                                 |  2 +
 .../design.md                                      | 73 ++++++++++++++++++++++
 .../proposal.md                                    | 29 +++++++++
 .../specs/command-replay-result-mapping/spec.md    | 36 +++++++++++
 .../tasks.md                                       | 30 +++++++++
 5 files changed, 170 insertions(+)

diff --git a/openspec/changes/avoid-mutating-command-dto-on-replay-remap/.openspec.yaml b/openspec/changes/avoid-mutating-command-dto-on-replay-remap/.openspec.yaml
new file mode 100644
index 00000000000..e8d4ccfe905
--- /dev/null
+++ b/openspec/changes/avoid-mutating-command-dto-on-replay-remap/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-06-08
diff --git a/openspec/changes/avoid-mutating-command-dto-on-replay-remap/design.md b/openspec/changes/avoid-mutating-command-dto-on-replay-remap/design.md
new file mode 100644
index 00000000000..52834520929
--- /dev/null
+++ b/openspec/changes/avoid-mutating-command-dto-on-replay-remap/design.md
@@ -0,0 +1,73 @@
+## Context
+
+Replay input remapping replaces recorded target and reference parameter bookmarks with actual bookmarks before command execution.
+The imported `CommandLogEntry` command DTO is also used for audit, participant inspection, retry, and future mapping lookup.
+If replay remapping writes replacements into that stored DTO, replay loses the original recorded input values and the UI can no longer show recorded versus actual bookmarks accurately.
+
+The replay flow already has a narrow remapping point immediately before `CommandExecutorService#executeCommand(...)`.
+That is the right place to ensure remapping works on an isolated execution DTO rather than the persisted command DTO.
+
+## Goals / Non-Goals
+
+**Goals:**
+
+- Ensure target remapping does not mutate `CommandLogEntry#getCommandDto()`.
+- Ensure reference parameter remapping does not mutate `CommandLogEntry#getCommandDto()`.
+- Ensure replay execution still receives remapped target and reference parameter values.
+- Preserve recorded DTO values for replayable command participants, inspection, and retry.
+- Add focused tests that fail if replay remapping mutates the stored DTO.
+
+**Non-Goals:**
+
+- Do not change command replay mapping SPI method signatures.
+- Do not change command export YAML shape.
+- Do not change replay result notification behavior.
+- Do not add persistence schema changes.
+
+## Decisions
+
+### Remap only a defensive command DTO copy
+
+The replay flow should create a defensive copy of the recorded command DTO before remapping targets or reference parameters.
+All bookmark replacement writes should apply to that copy only.
+The copied DTO is then passed to command execution.
+
+Alternative considered: remap the stored DTO and restore it afterward.
+That would be fragile around exceptions, transaction rollback boundaries, and future code paths that inspect the DTO during replay.
+
+### Keep recorded and execution DTO responsibilities separate
+
+The stored command DTO should remain the recorded input contract.
+The remapped execution DTO should be treated as a transient execution artifact.
+Replayable participant display should continue deriving recorded bookmarks from the stored DTO and actual bookmarks from mapping lookup or replay success state.
+
+Alternative considered: persist both recorded and effective replay DTOs.
+That would add data model complexity before there is a requirement to retain the effective execution shape.
+
+### Test target and parameter mutation independently
+
+Target and reference parameter remapping mutate different nested DTO structures.
+Tests should assert that replay execution receives replacements and that the original target and parameter references remain unchanged on the command log entry after replay mapping.
+
+Alternative considered: rely on participant display tests only.
+Those tests can miss direct DTO mutation if they use cached or mocked participant data.
+
+## Risks / Trade-offs
+
+- [Risk] The defensive copy utility might be shallow for some command DTO nested structures.
+  → Mitigate with tests that inspect nested targets and reference parameters after replay remapping.
+- [Risk] Copying command DTOs on every replay adds overhead.
+  → Mitigate by copying only during replay execution, where command execution dominates cost.
+- [Risk] Existing tests may have assumed remapping mutates the stored DTO.
+  → Mitigate by updating tests to assert recorded versus execution DTO separation.
+
+## Migration Plan
+
+No schema migration is expected.
+Existing command log entries remain unchanged.
+After deployment, replay will preserve recorded command DTO values even when mapping replaces targets or reference parameters at execution time.
+Rollback by reverting the defensive-copy/remapping change if unexpected replay execution regressions appear.
+
+## Open Questions
+
+- Should replay diagnostics expose the transient remapped execution DTO directly, or are participant actual bookmark values sufficient?
diff --git a/openspec/changes/avoid-mutating-command-dto-on-replay-remap/proposal.md b/openspec/changes/avoid-mutating-command-dto-on-replay-remap/proposal.md
new file mode 100644
index 00000000000..aeaa93ad4ac
--- /dev/null
+++ b/openspec/changes/avoid-mutating-command-dto-on-replay-remap/proposal.md
@@ -0,0 +1,29 @@
+## Why
+
+Command replay remapping changes target and reference parameter bookmarks before execution, but the imported `CommandLogEntry` command DTO is the audit record of what was exported and imported.
+If replay remapping mutates that recorded DTO, later inspection, retries, and mapping diagnostics can no longer distinguish the recorded bookmark from the actual replay bookmark.
+
+## What Changes
+
+- Ensure replay target remapping operates on a replay-time copy of the command DTO.
+- Ensure replay reference parameter remapping operates on a replay-time copy of the command DTO.
+- Preserve the original command DTO stored on the `CommandLogEntry` after replay, retry, or replay failure.
+- Add tests proving remapped targets and reference parameters are supplied to replay execution without mutating recorded command data.
+- Preserve existing replay mapping SPI contracts and replay result mapping behavior.
+
+## Capabilities
+
+### New Capabilities
+
+None.
+
+### Modified Capabilities
+
+- `command-replay-result-mapping`: Strengthen replay input remapping requirements so remapped targets and reference parameters never mutate recorded command DTO data.
+
+## Impact
+
+- Replayable command replay-or-retry flow in the command-log applib replay layer.
+- Command DTO copy/remapping utilities used immediately before command execution.
+- Tests for target and reference parameter remapping, replay retry, and recorded DTO inspection.
+- No schema, YAML, or SPI signature changes are expected.
diff --git a/openspec/changes/avoid-mutating-command-dto-on-replay-remap/specs/command-replay-result-mapping/spec.md b/openspec/changes/avoid-mutating-command-dto-on-replay-remap/specs/command-replay-result-mapping/spec.md
new file mode 100644
index 00000000000..80691996ea7
--- /dev/null
+++ b/openspec/changes/avoid-mutating-command-dto-on-replay-remap/specs/command-replay-result-mapping/spec.md
@@ -0,0 +1,36 @@
+## MODIFIED Requirements
+
+### Requirement: Replay input remapping does not mutate recorded command data
+The system SHALL preserve the imported command log entry's recorded command DTO when applying replay-time target or reference parameter remapping.
+Replay input remapping SHALL affect the command DTO supplied to replay execution, not the recorded command DTO retained for audit and inspection.
+When target remapping supplies a replacement bookmark, the replay execution DTO SHALL use the replacement target bookmark and the recorded command DTO SHALL retain the original target bookmark.
+When reference parameter remapping supplies a replacement bookmark, the replay execution DTO SHALL use the replacement parameter reference bookmark and the recorded command DTO SHALL retain the original parameter reference bookmark.
+Replay retry SHALL start from the recorded command DTO and MUST NOT reuse a previously remapped execution DTO as recorded input.
+Replay failure MUST NOT leave remapped target or reference parameter values in the recorded command DTO.
+
+#### Scenario: Remapped replay target preserves recorded command
+- **WHEN** command replay remaps recorded target bookmark `demoCustomer:1` to actual target bookmark `demoCustomer:2`
+- **THEN** the replay execution receives target bookmark `demoCustomer:2`
+- **AND** the imported command log entry still records target bookmark `demoCustomer:1`
+
+#### Scenario: Remapped replay reference parameter preserves recorded command
+- **WHEN** command replay remaps action reference parameter `customer` from recorded bookmark `demoCustomer:1` to actual bookmark `demoCustomer:2`
+- **THEN** the replay execution receives reference parameter `customer` with bookmark `demoCustomer:2`
+- **AND** the imported command log entry still records reference parameter `customer` with bookmark `demoCustomer:1`
+
+#### Scenario: Replay retry starts from recorded target bookmark
+- **GIVEN** a first replay remaps recorded target bookmark `demoCustomer:1` to actual target bookmark `demoCustomer:2`
+- **WHEN** the command is replayed or retried again
+- **THEN** replay input remapping is evaluated against recorded target bookmark `demoCustomer:1`
+- **AND** the stored command DTO does not use `demoCustomer:2` as the recorded target
+
+#### Scenario: Replay retry starts from recorded reference parameter bookmark
+- **GIVEN** a first replay remaps action reference parameter `customer` from recorded bookmark `demoCustomer:1` to actual bookmark `demoCustomer:2`
+- **WHEN** the command is replayed or retried again
+- **THEN** replay input remapping is evaluated against recorded parameter bookmark `demoCustomer:1`
+- **AND** the stored command DTO does not use `demoCustomer:2` as the recorded parameter reference
+
+#### Scenario: Replay failure preserves recorded command DTO
+- **WHEN** command replay remaps a recorded target or reference parameter bookmark before execution
+- **AND** replay execution fails
+- **THEN** the imported command log entry still records the original target and reference parameter bookmarks
diff --git a/openspec/changes/avoid-mutating-command-dto-on-replay-remap/tasks.md b/openspec/changes/avoid-mutating-command-dto-on-replay-remap/tasks.md
new file mode 100644
index 00000000000..f1f8b4e5c35
--- /dev/null
+++ b/openspec/changes/avoid-mutating-command-dto-on-replay-remap/tasks.md
@@ -0,0 +1,30 @@
+## 1. Locate Replay Remapping Flow
+
+- [ ] 1.1 Identify where `ReplayableCommand` obtains the recorded `CommandDto` from `CommandLogEntry` for replay.
+- [ ] 1.2 Identify where target bookmarks are remapped before command execution.
+- [ ] 1.3 Identify where reference action parameter bookmarks are remapped before command execution.
+- [ ] 1.4 Identify the command DTO copy utility currently used by the replay flow.
+
+## 2. Preserve Recorded Command DTO
+
+- [ ] 2.1 Ensure replay remapping always operates on a defensive copy of the recorded command DTO.
+- [ ] 2.2 Ensure target bookmark replacement writes only to the replay execution DTO.
+- [ ] 2.3 Ensure reference parameter bookmark replacement writes only to the replay execution DTO.
+- [ ] 2.4 Ensure `CommandLogEntry#getCommandDto()` retains recorded target and reference parameter bookmarks after replay remapping.
+- [ ] 2.5 Ensure replay failures do not leave remapped values in the recorded command DTO.
+
+## 3. Preserve Replay and Inspection Behavior
+
+- [ ] 3.1 Ensure command execution still receives remapped target bookmarks when mapping lookup provides replacements.
+- [ ] 3.2 Ensure command execution still receives remapped reference parameter bookmarks when mapping lookup provides replacements.
+- [ ] 3.3 Ensure retry starts from the original recorded command DTO rather than a previous execution DTO.
+- [ ] 3.4 Ensure replayable command participant inspection still shows recorded bookmarks from the stored DTO and actual bookmarks from mapping lookup or replay success.
+
+## 4. Tests and Verification
+
+- [ ] 4.1 Add a unit test proving remapped target replay does not mutate the recorded command DTO.
+- [ ] 4.2 Add a unit test proving remapped reference parameter replay does not mutate the recorded command DTO.
+- [ ] 4.3 Add a unit test proving replay failure preserves recorded command DTO target and parameter bookmarks.
+- [ ] 4.4 Add or update tests proving replay execution receives the remapped execution DTO.
+- [ ] 4.5 Run targeted commandlog applib replay mapping tests.
+- [ ] 4.6 Run `openspec status --change avoid-mutating-command-dto-on-replay-remap` and address any artifact validation issues.