7.4 KiB
Application Outbox Failure Reporting Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Make application-core framework/logging-free while preserving one safe structured ERROR
after each confirmed outbox FAILED/DEAD transition.
Architecture: The application owns a narrow typed reporting port and safe report value. Messaging renders the report through SLF4J, and bootstrap only injects it. Transition state remains authoritative; reporter failures are non-authoritative and contained.
Tech Stack: Java 21 records, JUnit Jupiter, AssertJ, Spring Boot 4 configuration, SLF4J 2 fluent logging, Logback capture tests, ArchUnit, Gradle Groovy DSL, dependency locking.
Task 1: Safe Application Report Contract
Files:
-
Create:
src/application-core/src/test/java/dev/caskeleton/application/outbox/OutboxRelayFailureReportTest.java -
Create:
src/application-core/src/main/java/dev/caskeleton/application/outbox/OutboxRelayFailureReport.java -
Create:
src/application-core/src/main/java/dev/caskeleton/application/outbox/OutboxRelayFailureReportPort.java -
Write factory, invariant, and reflection-whitelist tests for the exact eight record components.
-
Run
./gradlew :application-core:test --tests '*OutboxRelayFailureReportTest' --console=plainand record the expected missing-type RED. -
Implement the immutable record, exact invariants, factories, and functional port.
-
Re-run the focused value test and record GREEN.
Task 2: Relay Reporting Behavior
Files:
-
Modify:
src/application-core/src/test/java/dev/caskeleton/application/outbox/PublishPendingOutboxEventsUseCaseTest.java -
Modify:
src/application-core/src/main/java/dev/caskeleton/application/outbox/PublishPendingOutboxEventsUseCase.java -
Modify direct test constructor sites under
src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/integration/outbox/ -
Add recording/throwing reporters and tests for exact FAILED/DEAD reports, all no-report paths, transition failure propagation, and reporter-failure continuation.
-
Run the relay test and record constructor/behavior RED.
-
Inject the reporter after the publish port, remove SLF4J, report only after successful transition, and contain reporter
RuntimeException. -
Update test-only direct constructors with explicit lambdas and re-run relay tests GREEN.
Task 3: Structured Messaging Adapter and Publish-Adapter Deduplication
Files:
-
Create:
src/adapter/outbound/messaging/src/test/java/dev/caskeleton/adapter/outbound/messaging/outbox/Slf4jOutboxRelayFailureReportAdapterTest.java -
Create:
src/adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/outbox/Slf4jOutboxRelayFailureReportAdapter.java -
Modify:
src/adapter/outbound/messaging/src/test/java/dev/caskeleton/adapter/outbound/messaging/outbox/OutboxMessagePublishAdapterTest.java -
Modify:
src/adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/outbox/OutboxMessagePublishAdapter.java -
Write Logback capture tests for exact ERROR count, fixed fields, throwable, retry-only time, unsafe-data absence, internal logging failure containment, and the adapter contract that
report(null)never throws. -
Run
./gradlew :adapter:outbound:messaging:test --tests '*Slf4jOutboxRelayFailureReportAdapterTest' --console=plainand record missing-type RED. -
Implement the SLF4J 2 fluent adapter and re-run GREEN.
-
Replace outbox publish WARN expectations with no-log and propagation expectations; run RED.
-
Remove
FailOpenDependencyLoggerfrom the outbox adapter and re-run its tests GREEN, leavingOutboundMessagePublisherunchanged.
Task 4: Unconditional Reporter Wiring
Files:
-
Modify:
src/adapter/outbound/messaging/src/main/java/dev/caskeleton/adapter/outbound/messaging/MessagingConfig.java -
Modify:
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/outbox/OutboxConfig.java -
Modify:
src/app-bootstrap/src/test/java/dev/caskeleton/adapter/outbound/OptionalAdapterBeanGatingTest.java -
Modify:
src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/outbox/OutboxConfigTest.java -
Add disabled and active context assertions for exactly one structured reporter bean.
-
Run
OptionalAdapterBeanGatingTestand record RED. -
Add the unconditional messaging reporter bean, use
disabledfor blank broker, update outbox publish adapter construction, and inject the port through bootstrap. -
Re-run the gating and outbox configuration tests GREEN.
Task 5: Application Dependency Purity
Files:
-
Modify:
src/build.gradle -
Modify:
src/application-core/build.gradle -
Mechanically regenerate only:
src/application-core/gradle.lockfile -
Add
verifyApplicationCoreDependencyPurity, wire it into:application-core:check, and run it against the current starter declaration to record RED. -
Give
application-coreonly JUnit Jupiter and AssertJ test dependencies while retaining the shared Boot test dependencies for every other leaf. -
Remove the application Spring Boot starter and re-run the purity task GREEN.
-
Run
./gradlew :application-core:resolveAndLockAll --write-locks --console=plain; confirm no other lockfile changes. -
Run application lock verification, tests, and compile/test runtime dependency reports.
Task 6: Non-Vacuous Diagnostic Architecture Rule
Files:
-
Modify:
src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/architecture/CleanArchitectureTest.java -
Create:
src/app-bootstrap/src/test/java/dev/caskeleton/application/architecture/violations/ApplicationDiagnosticFrameworkViolation.java -
Modify:
src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/architecture/ArchitectureViolationFixtureTest.java -
Add the violation fixture inside the exact
dev.caskeleton.application..rule scope and its mutation assertion; run it before the rule to record RED. -
Add
APPLICATION_HAS_NO_DIAGNOSTIC_FRAMEWORK, scoped exactly todev.caskeleton.application.., for SLF4J, JUL, Logback, Log4j, and Micrometer. -
Run the mutation test and production
CleanArchitectureTestGREEN.
Task 7: Documentation and Verification
Files:
-
Modify:
src/application-core/CLAUDE.md -
Modify:
src/application-core/README.md -
Modify:
src/adapter/outbound/messaging/CLAUDE.md -
Modify:
src/adapter/outbound/messaging/README.md -
Modify relevant wiring guidance in
src/app-bootstrap/README.md -
Document the framework-free application contract, typed report semantics, messaging ownership, duplicate-log rule, and bootstrap wiring-only role.
-
Run focused application, messaging, gating, architecture mutation, production architecture, and available outbox integration tests.
-
Run
verifyCleanArchitectureDependencies, dependency evidence reports, andcheck. -
Run required safety greps,
git diff --check, andgit status --short; report any skip or remaining risk. -
Hand the exact LLM Wiki capture responsibility and evidence back to the top-level controller; do not write the vault from this dispatched scope.
No step authorizes staging, committing, amending, pushing, public-path changes, CI changes, module
registry changes, or .harness changes.