Files
tech-log-backend/docs/superpowers/plans/2026-07-28-httpclient-canonical-zero-binding.md

6.7 KiB

HTTP Client Canonical Zero-Binding Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development or superpowers:executing-plans. Repository policy overrides the skill's commit steps: do not stage, commit, amend, or push.

Goal: Make HTTP client activation an explicit canonical composition decision and prove that the default zero-binding state creates no client, executor, shutdown guard, retry/circuit-breaker registry, or transport resource.

Architecture: adapter:outbound:httpclient owns strict canonical configuration, immutable binding/provider/catalog/readiness registries, and a pure activation resolver. app-bootstrap owns the composition root that binds canonical properties and publishes an inert capability descriptor. The existing JDK OutboundHttpClient remains an explicitly constructed R1 migration facade; its legacy settings and infrastructure configuration must no longer be discovered automatically.

Scope boundary: This increment does not add Apache HC5, a provider factory, a real semantic upstream binding, hard wire cancellation, TLS/DNS/proxy/auth, or an R2 readiness claim. Every current ACTIVE selection must fail closed because the only derived readiness card remains NOT_IMPLEMENTED.


Task 1: Add strict canonical selection and provider binding models

Files:

  • Create: src/adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/activation/HttpClientExpectedState.java

  • Create: src/adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/activation/HttpClientCanonicalConfiguration.java

  • Create: src/adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/activation/HttpClientCanonicalConfigurationBinder.java

  • Test: src/adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/activation/HttpClientCanonicalConfigurationBinderTest.java

  • Write RED tests for the canonical YAML shape under ca-skeleton.capabilities.http-client and ca-skeleton.providers.http-client.

  • Reject unknown fields, malformed IDs, unknown expected state, and any legacy input entering canonical composition, including the DISABLED state.

  • Preserve OutboundHttpSettings constructors as migration API, but remove its global @ConfigurationPropertiesScan participation.

  • Keep provider definitions inert data; configuration alone must not create a transport.

Task 2: Add catalog/readiness registries and pure fail-closed activation resolution

Files:

  • Create: src/adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/activation/HttpOperationCatalogRegistry.java

  • Create: src/adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/activation/HttpClientReadinessCardRegistry.java

  • Create: src/adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/activation/ResolvedHttpClientCapability.java

  • Create: src/adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/activation/HttpClientActivationResolver.java

  • Test: src/adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/activation/HttpClientActivationResolverTest.java

  • Prove DISABLED + bindings 0 + provider definitions 0 resolves to DISABLED_VERIFIED, selected binding/card count 0.

  • Reject DISABLED with bindings or provider resources.

  • Reject ACTIVE with zero bindings.

  • For every binding, require an exact provider, provider destination, and registered operation catalog for the same destination.

  • Derive the httpclient-static-buffered card from each current buffered classic profile.

  • Mark that card NOT_IMPLEMENTED; reject ACTIVE before any provider resource/factory exists.

Task 3: Move HTTP Spring activation to the composition root

Files:

  • Modify: src/adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/OutboundHttpClientConfig.java

  • Modify: src/adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/OutboundHttpSettings.java

  • Modify: src/adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/resilience/OutboundHttpResilienceConfig.java

  • Create: src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/httpclient/HttpClientCompositionConfig.java

  • Modify: src/app-bootstrap/src/main/resources/application.yml

  • Modify: src/app-bootstrap/src/test/java/dev/caskeleton/adapter/outbound/OptionalAdapterBeanGatingTest.java

  • Test: src/app-bootstrap/src/test/java/dev/caskeleton/bootstrap/httpclient/HttpClientCompositionConfigTest.java

  • Detach legacy HTTP infrastructure from component/configuration-properties scanning while preserving direct constructors/factory methods used by forks and existing unit tests.

  • Register only canonical configuration, immutable registries, resolver, and inert descriptor in the composition root.

  • Default application YAML to canonical expected-state: DISABLED, empty bindings, and empty provider definitions; keep legacy migration keys out of both main and test application YAML.

  • Assert zero OutboundHttpClient, RestClient, OutboundCallExecutor, OutboundHttpShutdownGuard, OutboundHttpResilience, RetryRegistry, and CircuitBreakerRegistry beans/resources in the default context.

  • Assert contradictory/ACTIVE configurations fail startup before resource construction.

  • Load the real application.yml in composition tests and prove ACTIVE reaches the NOT_IMPLEMENTED readiness card rather than a legacy conflict.

Task 4: Document exact readiness and verify

Files:

  • Modify: src/adapter/outbound/httpclient/README.md

  • Modify: src/adapter/outbound/httpclient/CLAUDE.md

  • Modify: docs/superpowers/specs/2026-07-27-httpclient-production-capability-design.md

  • Modify: docs/superpowers/plans/2026-07-28-httpclient-production-capability-foundation.md

  • Mark canonical zero-binding as implemented without marking HTTP R2 complete.

  • Keep HC5/provider resources/security/real-network qualification explicitly unimplemented.

  • Run focused tests:

cd src
./gradlew :adapter:outbound:httpclient:check --rerun-tasks --console=plain
./gradlew :app-bootstrap:check --rerun-tasks --console=plain
./gradlew :sample-portfolio:test --rerun-tasks --console=plain
./gradlew verifyCleanArchitectureDependencies verifyConfigurationPropertiesProcessor \
  verifyEnvKeys verifyPublicPathSnapshot --console=plain

Do not edit unrelated notification, messaging, object-storage, JPA, MongoDB, GraphQL, gRPC, web, or WebSocket files.