Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions .agents/tasks/de-event-sourcing-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,16 @@ Get the ADR reviewed and approved by the product owner before Phase B.

Open points with recommendations:

| # | Question | Recommendation |
|----|-----------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| A1 | Name and shape of the import receptor annotation | **Revised 2026-07-05 (ADR D1): event import is dropped entirely** — usage research found one dormant production usage in six years. Superseded original recommendation: an `@Import` receptor mirroring `@Assign` with routing via `setupImportRouting` |
| A2 | Fate of classes that still declare `@Apply` after cutover | Fail fast: `AggregateClass` (**and `AggregatePartClass`**) raises a `ModelError` at model-building time with a migration message. Silent non-invocation is unacceptable. (`@Apply` on a `ProcessManager` is invalid and unsupported — the one such downstream fixture is fixed in `model-tools`; see Phase E) |
| A3 | Version advancement | Aggregate version advances **+1 per command handler, not per event** (product decision) — the `ProcessManager` semantics. Reuse the PM path: one `CommandDispatchingPhase` + `VersionIncrement.sequentially`. Emitted events carry the resulting version; the per-event `VersionSequence` is removed. Confirm/adjust emitted-event version stamping and document the change from prior per-event versions. Own test |
| # | Question | Recommendation |
|----|-----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| A1 | Name and shape of the import receptor annotation | **Revised 2026-07-05 (ADR D1): event import is dropped entirely** — usage research found one dormant production usage in six years. Superseded original recommendation: an `@Import` receptor mirroring `@Assign` with routing via `setupImportRouting` |
| A2 | Fate of classes that still declare `@Apply` after cutover | Fail fast: `AggregateClass` (**and `AggregatePartClass`**) raises a `ModelError` at model-building time with a migration message. Silent non-invocation is unacceptable. (`@Apply` on a `ProcessManager` is invalid and unsupported — the one such downstream fixture is fixed in `model-tools`; see Phase E) |
| A3 | Version advancement | Aggregate version advances **+1 per command handler, not per event** (product decision) — the `ProcessManager` semantics. Reuse the PM path: one `CommandDispatchingPhase` + `VersionIncrement.sequentially`. Emitted events carry the resulting version; the per-event `VersionSequence` is removed. Confirm/adjust emitted-event version stamping and document the change from prior per-event versions. Own test |
| A4 | State mutation without emitted events | Command handlers and reactors work the same way (**may** update state via `builder()`, may call `setArchived()`/`setDeleted()` — state update never forced), differing only in emission: `@Assign` **must emit ≥1 event or reject**; `@React` **may emit zero events**. *(The `@Import` clause originally here is void — event import is dropped; ADR D1, revised 2026-07-05.)* No blanket "builder touched but no event → reject" and no new "must change state" guard. Lifecycle-flag flips that lived in appliers migrate into the handler body. See ADR D4 |
| A5 | Deduplication + recent-history window | Delivery layer owns dedup; the aggregate `IdempotencyGuard` is **opt-in per repository, off by default** (`useIdempotencyGuard()`), kept so it can be removed later. Recent history loaded **lazily on demand** from the journal tail, bounded by `historyDepth` (default 100, = old `DEFAULT_SNAPSHOT_TRIGGER`; per-repository = per-aggregate-type). Guard-off dispatch does only the state read; guard-on pays the bounded journal read. Delivery durable dedup needs a configured `deduplicationWindow` in production. See ADR D5 |
| A6 | Rejection/exception semantics | Transaction rollback discards builder mutations; nothing is stored or posted. Verify `Transaction` rollback covers this; add tests |
| A7 | Journal trimming without snapshots | Snapshot-index `truncateOlderThan` dies with snapshots. Phase D introduces count/date-based trimming; until then journal grows append-only |
| A8 | `state()` visibility inside an open transaction | Handlers read pre-transaction state, mutate via `builder()` (same shape as `ProcessManager`) |
| A5 | Deduplication + recent-history window | Delivery layer owns dedup; the aggregate `IdempotencyGuard` is **opt-in per repository, off by default** (`useIdempotencyGuard()`), kept so it can be removed later. Recent history loaded **lazily on demand** from the journal tail, bounded by `historyDepth` (default 100, = old `DEFAULT_SNAPSHOT_TRIGGER`; per-repository = per-aggregate-type). Guard-off dispatch does only the state read; guard-on pays the bounded journal read. Delivery durable dedup needs a configured `deduplicationWindow` in production. See ADR D5 |
| A6 | Rejection/exception semantics | Transaction rollback discards builder mutations; nothing is stored or posted. Verify `Transaction` rollback covers this; add tests |
| A7 | Journal trimming without snapshots | Snapshot-index `truncateOlderThan` dies with snapshots. Phase D introduces count/date-based trimming; until then journal grows append-only |
| A8 | `state()` visibility inside an open transaction | Handlers read pre-transaction state, mutate via `builder()` (same shape as `ProcessManager`) |

## Phase B — Core runtime cutover (`server` module)

Expand Down Expand Up @@ -448,8 +448,8 @@ repos except the deprecated annotation type itself.**
| **Aggregate version stops advancing** once replay is gone | A3: reuse the PM per-dispatch `VersionIncrement.sequentially` (+1 per command); dedicated test asserting version increments by exactly 1 per command, regardless of event count |
| Dropping the eager aggregate dedup guard could let duplicates through after a JVM restart / cache eviction when no delivery `deduplicationWindow` is set | Guard kept as opt-in backstop (A5/D5); document that production sets a `deduplicationWindow`; when guard on, verify `clearEnrichments` keeps `pastMessage` and test journal-tail dedup with no snapshot |
| Accidentally removing the shared `EventPlayer` type breaks `Projection` | Drop only `Aggregate`'s `implements`; keep the entity-layer type |
| A4: over-strict emission guard rejects a legal empty `@React` | Per-receptor rule (only `@Assign` must emit ≥1 event); tests for an empty reactor and a lifecycle-only handler |
| Removing event import breaks unknown external users of `ImportBus` / `BlackBox.importsEvent` | Org-wide research (2026-07-05, ADR D1 revision) found none outside the dormant `auth`; replacement idioms documented in the migration guide (PR-B3) |
| A4: over-strict emission guard rejects a legal empty `@React` | Per-receptor rule (only `@Assign` must emit ≥1 event); tests for an empty reactor and a lifecycle-only handler |
| Removing event import breaks unknown external users of `ImportBus` / `BlackBox.importsEvent` | Org-wide research (2026-07-05, ADR D1 revision) found none outside the dormant `auth`; replacement idioms documented in the migration guide (PR-B3) |
| PR-B2 is large and cannot land green-per-commit | Accept it as one atomic commit; fixture edits are mechanical and reviewable in bulk; keep runtime diff Java-minimal |
| Storage backends (incl. `delivery-server` redis/hazelcast) break on state-write semantics | Phase C smoke builds all vendors before the rollout wave |
| `AggregatePart` silently breaks | PR-B2 step 11 covers `AggregatePart`/`AggregatePartClass`/`PartFactory` in the A2 fail-fast and the state-load path |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ object Validation {
/**
* The version of the Validation library artifacts.
*/
const val version = "2.0.0-SNAPSHOT.446"
const val version = "2.0.0-SNAPSHOT.447"

const val group = Spine.toolsGroup
private const val prefix = "validation"
Expand Down
Loading
Loading