# 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=plain` and 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=plain` and 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 `FailOpenDependencyLogger` from the outbox adapter and re-run its tests GREEN, leaving `OutboundMessagePublisher` unchanged. ### 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 `OptionalAdapterBeanGatingTest` and record RED. - [ ] Add the unconditional messaging reporter bean, use `disabled` for 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-core` only 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 to `dev.caskeleton.application..`, for SLF4J, JUL, Logback, Log4j, and Micrometer. - [ ] Run the mutation test and production `CleanArchitectureTest` GREEN. ### 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, and `check`. - [ ] Run required safety greps, `git diff --check`, and `git 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.