106 lines
5.4 KiB
Markdown
106 lines
5.4 KiB
Markdown
# Outbox Transport-Only Cutover Implementation Plan
|
|
|
|
**Goal:** Preserve canonical integration-event bytes and metadata inside the existing legacy `outbox_event` authority, then route canonical claimed rows through the messaging platform while legacy rows keep the current broker path.
|
|
|
|
**Spec:** `docs/superpowers/specs/2026-09-18-outbox-transport-only-cutover-design.md`
|
|
|
|
## Constraints
|
|
|
|
- Preserve all existing uncommitted work. No reset/checkout/stage/commit/amend/push.
|
|
- Do not activate or switch to `POLLING_V2`.
|
|
- Do not synthesize missing canonical metadata for legacy rows.
|
|
- Do not re-encode a persisted canonical envelope.
|
|
- One claimed row goes through exactly one publish branch.
|
|
- Default configuration remains legacy-compatible and canonical transport is off.
|
|
|
|
### Task 1 — Split canonical and legacy append ports
|
|
|
|
- [x] Create `LegacyOutboxAppendPort` with the current `NewOutboxEvent` signature.
|
|
- [x] Change `OutboxAppendPort` to accept `ValidatedIntegrationEvent`.
|
|
- [x] Move all current raw production consumers and their tests to `LegacyOutboxAppendPort`.
|
|
- [x] Make `OutboxStoreAdapter` implement `LegacyOutboxAppendPort` only.
|
|
- [x] Run `:application-core:test` and focused sample/outbox compile tests.
|
|
|
|
### Task 2 — Add additive canonical columns to `outbox_event`
|
|
|
|
- [x] Add the next PostgreSQL migration after V12.
|
|
- [x] Widen event/correlation identifiers as required.
|
|
- [x] Add canonical metadata, exact `BYTEA`, hashes/revisions, and all-or-none check constraints.
|
|
- [x] Extend `OutboxEventEntity` mappings.
|
|
- [x] Update migration history expectations.
|
|
- [x] Add real PostgreSQL integration assertions for legacy rows and canonical shape constraints.
|
|
|
|
### Task 3 — Implement canonical append adapter
|
|
|
|
- [x] Add `CanonicalOutboxAppendAdapter`.
|
|
- [x] Strictly validate UTF-8 compatibility projection.
|
|
- [x] Persist every canonical field and exact `envelopeBytes`.
|
|
- [x] Preserve old required columns for legacy relay/storage compatibility.
|
|
- [x] Add unit tests for byte equality, field mapping and invalid UTF-8.
|
|
- [x] Gate bean exposure on `ca-skeleton.outbox.canonical-transport-enabled=true`.
|
|
|
|
### Task 4 — Split the claimed row model
|
|
|
|
- [x] Add sealed `ClaimedOutboxEvent`.
|
|
- [x] Keep `OutboxEvent` as legacy subtype.
|
|
- [x] Add `CanonicalClaimedOutboxEvent` carrying reconstructed `ValidatedIntegrationEvent`.
|
|
- [x] Change `OutboxStorePort.claimBatch` to return the sealed type.
|
|
- [x] Map all-canonical rows to canonical subtype and all-null rows to legacy subtype.
|
|
- [x] Reject partial canonical rows.
|
|
- [x] Update legacy relay tests without changing its state-machine semantics.
|
|
|
|
### Task 5 — Route canonical claims through the platform
|
|
|
|
- [x] Update `OutboxMessagePublishPort` to accept `ClaimedOutboxEvent`.
|
|
- [x] Extend `OutboxMessagePublishAdapter` with canonical `IntegrationEventPublishPort`.
|
|
- [x] Legacy subtype uses only `MessageBroker`.
|
|
- [x] Canonical subtype uses only the application canonical publish port and exact stored bytes.
|
|
- [x] Add focused branch-isolation and outcome tests.
|
|
|
|
### Task 6 — Add explicit activation and composition validation
|
|
|
|
- [x] Add `canonicalTransportEnabled` to `OutboxSettings` and `config/outbox.yml`, default false.
|
|
- [x] Startup fails when canonical transport is enabled but no `IntegrationEventPublishPort` exists.
|
|
- [x] Relay-enabled compatibility deployment still requires the legacy broker until a later zero-legacy-backlog proof.
|
|
- [x] Default-off composition keeps the existing legacy path.
|
|
- [x] Enabled composition exposes the canonical append/publish path without a second scheduler.
|
|
- [x] Update configuration docs/SSOT.
|
|
|
|
### Task 7 — Regression and architecture verification
|
|
|
|
- [x] `:application-core:check`
|
|
- [x] `:adapter:outbound:persistence-jpa:check`
|
|
- [x] focused PostgreSQL migration/outbox integration lane
|
|
- [x] `:adapter:outbound:messaging:check`
|
|
- [ ] `:sample-portfolio:check` — blocked by pre-existing `JpaLiveEventReplayAdapter` missing `Duration` wiring; the same 3 `SampleApplicationContextTest` failures reproduce on clean HEAD.
|
|
- [x] focused sample outbox regression tests (`PosterEventPublisherTest`, `CreateWorkLogOutboxTest`, `WorkLogUseCasesTest`, `WorkLogAuthorizationContractTest`)
|
|
- [x] `:app-bootstrap:architectureTest :app-bootstrap:systemTest`
|
|
- [x] `verifyCleanArchitectureDependencies`
|
|
- [x] `:app-bootstrap:verifyEnvKeys`
|
|
- [x] static scans: no platform runtime/Kafka import in canonical bridge
|
|
- [x] `git diff --check`
|
|
- [x] no separate LLM Wiki branch-note warranted; spec, plan, module README/CLAUDE and configuration reference carry the implementation decision.
|
|
|
|
## Verification result
|
|
|
|
Transport-only cutover implementation is complete for this slice.
|
|
|
|
Passed:
|
|
- `:application-core:check`
|
|
- `:adapter:outbound:persistence-jpa:check`
|
|
- `:adapter:outbound:persistence-jpa:postgresqlMigrationIntegrationTest`
|
|
- `:adapter:outbound:messaging:check`
|
|
- focused sample outbox regression tests
|
|
- `:app-bootstrap:test`
|
|
- focused `:app-bootstrap:integrationTest` outbox append + row-lifecycle contracts
|
|
- `:app-bootstrap:architectureTest`
|
|
- `:app-bootstrap:systemTest`
|
|
- `verifyCleanArchitectureDependencies`
|
|
- `:app-bootstrap:verifyEnvKeys`
|
|
- `git diff --check`
|
|
|
|
Known unrelated blocker:
|
|
- full `:sample-portfolio:check` still fails only the 3 previously documented `SampleApplicationContextTest` cases because `JpaLiveEventReplayAdapter` requires an unbound `Duration` bean. This reproduces on clean HEAD and was not introduced by this cutover.
|
|
|
|
Publication authority remains `LEGACY_POLLING`; no code path in this slice activates `POLLING_V2`.
|