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/07 14:49:11 UTC
(causeway) 20/50: CAUSEWAY-4014: proposes replay mapping command interaction id
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch CAUSEWAY-4014
in repository https://gitbox.apache.org/repos/asf/causeway.git
commit 425228138a2fd1e80c4d54eef216e21eddedb7e5
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Sun Jun 7 09:12:38 2026 +0100
CAUSEWAY-4014: proposes replay mapping command interaction id
---
.../.openspec.yaml | 2 +
.../design.md | 43 ++++++++++++++++++++++
.../proposal.md | 27 ++++++++++++++
.../specs/command-replay-result-mapping/spec.md | 22 +++++++++++
.../spec.md | 37 +++++++++++++++++++
.../tasks.md | 32 ++++++++++++++++
6 files changed, 163 insertions(+)
diff --git a/openspec/changes/capture-replay-mapping-command-interaction-id/.openspec.yaml b/openspec/changes/capture-replay-mapping-command-interaction-id/.openspec.yaml
new file mode 100644
index 00000000000..11967fcb6a7
--- /dev/null
+++ b/openspec/changes/capture-replay-mapping-command-interaction-id/.openspec.yaml
@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-06-07
diff --git a/openspec/changes/capture-replay-mapping-command-interaction-id/design.md b/openspec/changes/capture-replay-mapping-command-interaction-id/design.md
new file mode 100644
index 00000000000..ada248d60a1
--- /dev/null
+++ b/openspec/changes/capture-replay-mapping-command-interaction-id/design.md
@@ -0,0 +1,43 @@
+## Context
+
+Replay result mappings are created when `CommandReplayMappingListener#onReplayResult(...)` receives the recorded result bookmark, actual result bookmark, and replayed `CommandLogEntry`.
+The existing `CommandReplayResultMapping` abstraction and concrete JDO/JPA entities store only recorded and actual bookmarks.
+The in-memory listener stores only the actual bookmark in a `Map<Bookmark, Bookmark>`.
+The replayed `CommandLogEntry` already exposes the interaction id, so the change can capture the originating interaction without changing the replay notification SPI signature.
+
+## Goals / Non-Goals
+
+**Goals:**
+- Store the replayed command interaction id that first created each replay result mapping.
+- Preserve that first interaction id when replay reports an existing mapping again.
+- Keep persistent and in-memory replay mapping behavior aligned.
+- Show the command interaction id in replay result mapping layout metadata.
+
+**Non-Goals:**
+- Do not add a new finder by command interaction id unless a later change requests it.
+- Do not change conflict policy semantics for repeated mappings.
+- Do not change the `CommandReplayMappingListener` method signatures.
+
+## Decisions
+
+- Reuse `CommandLogEntry#getInteractionId()` as the source of the mapping origin.
+ The replay notification already receives the command log entry, so this avoids an SPI change and keeps custom listener compatibility.
+ The alternative was to add an explicit interaction id parameter to `onReplayResult(...)`, but that would create broader API churn without adding information.
+
+- Add `commandInteractionId` to the abstract applib mapping contract and to concrete JDO/JPA entities as a nullable `UUID` property.
+ Nullable storage protects upgrades and existing rows that predate the field.
+ The alternative was a non-null field, but that would require a data migration for existing mappings and complicate rollout.
+
+- Extend repository creation to accept the command interaction id, while preserving a compatibility overload if useful during implementation.
+ The persistent listener should create new rows with the interaction id and should not mutate existing rows during idempotent or conflict handling.
+ The alternative was to set the field after creation, but one creation path keeps the persistence contract simpler and easier to test.
+
+- Replace the in-memory listener value type with a small mapping value that stores both actual bookmark and command interaction id.
+ This keeps the in-memory storage strategy semantically equivalent to persistent storage.
+ The alternative was to leave in-memory storage unchanged, but that would make the data structure diverge from the new mapping contract.
+
+## Risks / Trade-offs
+
+- Existing persisted rows will have no command interaction id after upgrade → Treat the property as optional and display it only when available.
+- JDO query classes may need regeneration after adding the field → Include generated-source refresh or targeted compile in implementation tasks.
+- Layout metadata can become stale if the property id differs from the Java getter name → Use `commandInteractionId` consistently in the property, column order, and fallback layout.
diff --git a/openspec/changes/capture-replay-mapping-command-interaction-id/proposal.md b/openspec/changes/capture-replay-mapping-command-interaction-id/proposal.md
new file mode 100644
index 00000000000..e7c31831af2
--- /dev/null
+++ b/openspec/changes/capture-replay-mapping-command-interaction-id/proposal.md
@@ -0,0 +1,27 @@
+## Why
+
+Replay result mappings currently show the recorded and actual bookmarks but not the command interaction that first created the mapping.
+Capturing the originating command interaction id improves auditability and makes it possible to trace a remapping back to the replayed command that produced it.
+
+## What Changes
+
+- Add the command interaction id that created a replay result mapping to the replay mapping data model.
+- Persist the command interaction id on new `CommandReplayResultMapping` entities for both JDO and JPA persistence modules.
+- Keep the originally stored command interaction id unchanged when replay reports a mapping that already exists.
+- Extend the in-memory replay mapping data structure so it tracks the originating command interaction id alongside the actual bookmark.
+- Update the replay result mapping layout metadata so the command interaction id is visible in the UI.
+
+## Capabilities
+
+### New Capabilities
+
+### Modified Capabilities
+- `command-replay-result-mapping`: Replay result mapping observations expose and retain the command interaction id that produced the mapping.
+- `persistent-command-replay-mapping-listener`: Persistent replay result mappings store and display the command interaction id that first created the mapping.
+
+## Impact
+
+- Affects the command log applib replay mapping SPI implementations and replay result mapping repository contract.
+- Affects the JDO and JPA command log persistence entity mappings and generated query classes if applicable.
+- Affects replay result mapping fallback layout XML and column order metadata.
+- Requires tests for new mapping creation, idempotent existing mappings, and UI/layout metadata.
diff --git a/openspec/changes/capture-replay-mapping-command-interaction-id/specs/command-replay-result-mapping/spec.md b/openspec/changes/capture-replay-mapping-command-interaction-id/specs/command-replay-result-mapping/spec.md
new file mode 100644
index 00000000000..046e224121c
--- /dev/null
+++ b/openspec/changes/capture-replay-mapping-command-interaction-id/specs/command-replay-result-mapping/spec.md
@@ -0,0 +1,22 @@
+## ADDED Requirements
+
+### Requirement: Replay result mapping observes command interaction id
+The system SHALL make the replayed command interaction id available when a replay result mapping observation is handled.
+The built-in replay mapping listener implementations SHALL capture the interaction id from the `CommandLogEntry` supplied to `onReplayResult(...)` when they create a new mapping.
+When the supplied command log entry has no interaction id, the system SHALL still record or retain the replay result mapping without an interaction id.
+The system MUST NOT require a `CommandReplayMappingListener` SPI signature change to expose this interaction id.
+
+#### Scenario: Replay result observation includes command interaction id
+- **WHEN** command replay succeeds for an imported command whose interaction id is `11111111-1111-1111-1111-111111111111`
+- **AND** the command has recorded result bookmark `demoInvoice:1`
+- **AND** replay execution returns actual result bookmark `demoInvoice:2`
+- **THEN** the built-in replay mapping listener records a replay result mapping associated with command interaction id `11111111-1111-1111-1111-111111111111`
+
+#### Scenario: Replay result observation has no command interaction id
+- **WHEN** command replay notifies a built-in replay mapping listener with recorded result bookmark `demoInvoice:1` and actual result bookmark `demoInvoice:2`
+- **AND** the supplied command log entry has no interaction id
+- **THEN** the built-in replay mapping listener records or retains the replay result mapping without a command interaction id
+
+#### Scenario: Existing SPI signature is preserved
+- **WHEN** an application implements `CommandReplayMappingListener#onReplayResult(Bookmark, Bookmark, CommandLogEntry)`
+- **THEN** the implementation remains source-compatible with the replay result mapping SPI
diff --git a/openspec/changes/capture-replay-mapping-command-interaction-id/specs/persistent-command-replay-mapping-listener/spec.md b/openspec/changes/capture-replay-mapping-command-interaction-id/specs/persistent-command-replay-mapping-listener/spec.md
new file mode 100644
index 00000000000..e4120621b8f
--- /dev/null
+++ b/openspec/changes/capture-replay-mapping-command-interaction-id/specs/persistent-command-replay-mapping-listener/spec.md
@@ -0,0 +1,37 @@
+## ADDED Requirements
+
+### Requirement: Persistent replay mappings retain originating command interaction id
+The persistent replay mapping listener SHALL store the replayed command interaction id when it creates a new replay result mapping and the command interaction id is available.
+The persistent replay mapping listener MUST NOT update the stored command interaction id when a replay result notification matches an existing mapping.
+The persistent replay mapping listener MUST NOT update the stored command interaction id when a replay result notification conflicts with an existing mapping and the configured conflict policy logs and continues.
+The persisted replay result mapping entity SHALL expose the command interaction id as an optional property.
+The JDO and JPA command log persistence modules SHALL provide storage for the command interaction id property.
+
+#### Scenario: New persistent mapping records command interaction id
+- **WHEN** command replay notifies the persistent listener that recorded result bookmark `demoInvoice:1` mapped to actual result bookmark `demoInvoice:2`
+- **AND** the replayed command interaction id is `11111111-1111-1111-1111-111111111111`
+- **THEN** the system persists a mapping with command interaction id `11111111-1111-1111-1111-111111111111`
+
+#### Scenario: Existing idempotent mapping keeps original command interaction id
+- **GIVEN** a persisted replay result mapping for recorded bookmark `demoInvoice:1` has actual bookmark `demoInvoice:2`
+- **AND** the mapping has command interaction id `11111111-1111-1111-1111-111111111111`
+- **WHEN** command replay later notifies the persistent listener that recorded result bookmark `demoInvoice:1` mapped to actual result bookmark `demoInvoice:2`
+- **AND** the later replayed command interaction id is `22222222-2222-2222-2222-222222222222`
+- **THEN** the persisted mapping keeps command interaction id `11111111-1111-1111-1111-111111111111`
+
+#### Scenario: Existing conflicting mapping keeps original command interaction id when conflict is logged
+- **GIVEN** the replay mapping conflict policy is configured to log and continue
+- **AND** a persisted replay result mapping for recorded bookmark `demoInvoice:1` has actual bookmark `demoInvoice:2`
+- **AND** the mapping has command interaction id `11111111-1111-1111-1111-111111111111`
+- **WHEN** command replay later notifies the persistent listener that recorded result bookmark `demoInvoice:1` mapped to actual result bookmark `demoInvoice:3`
+- **AND** the later replayed command interaction id is `22222222-2222-2222-2222-222222222222`
+- **THEN** the persisted mapping keeps command interaction id `11111111-1111-1111-1111-111111111111`
+
+### Requirement: Persistent replay mapping layout displays command interaction id
+The system SHALL include the command interaction id property in the fallback layout metadata for persisted replay result mappings.
+The system SHALL include the command interaction id in replay result mapping column order metadata when such metadata is provided.
+
+#### Scenario: User views replay mapping command interaction id
+- **WHEN** a persisted replay result mapping has command interaction id `11111111-1111-1111-1111-111111111111`
+- **AND** a user views the replay result mapping
+- **THEN** the mapping layout displays the command interaction id
diff --git a/openspec/changes/capture-replay-mapping-command-interaction-id/tasks.md b/openspec/changes/capture-replay-mapping-command-interaction-id/tasks.md
new file mode 100644
index 00000000000..5b5834041cf
--- /dev/null
+++ b/openspec/changes/capture-replay-mapping-command-interaction-id/tasks.md
@@ -0,0 +1,32 @@
+## 1. Applib Mapping Contract
+
+- [ ] 1.1 Add an optional `commandInteractionId` property to `CommandReplayResultMapping` with domain event metadata and accessors.
+- [ ] 1.2 Update `CommandReplayResultMapping#init(...)` to accept and set the command interaction id while preserving bookmark initialization.
+- [ ] 1.3 Update `CommandReplayResultMappingRepository#createAndPersist(...)` and `CommandReplayResultMappingRepositoryAbstract` to create mappings with the command interaction id.
+- [ ] 1.4 Preserve compatibility where useful by delegating any existing two-bookmark creation path to the new creation path with a null command interaction id.
+
+## 2. Replay Mapping Listener Implementations
+
+- [ ] 2.1 Update `CommandReplayMappingListenerPersistent` to pass `CommandLogEntry#getInteractionId()` when creating a new persistent mapping.
+- [ ] 2.2 Ensure `CommandReplayMappingListenerPersistent` does not update `commandInteractionId` for idempotent existing mappings or logged conflicts.
+- [ ] 2.3 Replace the in-memory listener value type with a mapping data structure that stores actual bookmark and command interaction id.
+- [ ] 2.4 Ensure in-memory listener lookup and conflict handling preserve existing behavior while retaining the first command interaction id.
+
+## 3. Persistence and Layout Metadata
+
+- [ ] 3.1 Add nullable command interaction id storage to the JDO `CommandReplayResultMapping` entity.
+- [ ] 3.2 Add nullable command interaction id storage to the JPA `CommandReplayResultMapping` entity.
+- [ ] 3.3 Regenerate or update JDO query classes if required by the added persistent field.
+- [ ] 3.4 Update `CommandReplayResultMapping.layout.fallback.xml` to display `commandInteractionId`.
+- [ ] 3.5 Update `CommandReplayResultMapping.columnOrder.fallback.txt` to include `commandInteractionId`.
+
+## 4. Tests and Validation
+
+- [ ] 4.1 Add applib tests proving new persistent mappings capture the replayed command interaction id.
+- [ ] 4.2 Add tests proving existing idempotent mappings keep their original command interaction id.
+- [ ] 4.3 Add tests proving logged conflict handling keeps the original command interaction id.
+- [ ] 4.4 Add in-memory listener tests for capturing and retaining the first command interaction id in the internal data structure.
+- [ ] 4.5 Add or update persistence integration tests for JDO and JPA mapping entities.
+- [ ] 4.6 Validate layout and column order metadata includes `commandInteractionId`.
+- [ ] 4.7 Run `openspec validate capture-replay-mapping-command-interaction-id --strict`.
+- [ ] 4.8 Run targeted Maven tests for commandlog applib, persistence-jdo, and persistence-jpa modules.