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

121 lines
6.7 KiB
Markdown

# 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`
- [x] Write RED tests for the canonical YAML shape under
`ca-skeleton.capabilities.http-client` and `ca-skeleton.providers.http-client`.
- [x] Reject unknown fields, malformed IDs, unknown expected state, and any legacy input entering
canonical composition, including the DISABLED state.
- [x] Preserve `OutboundHttpSettings` constructors as migration API, but remove its global
`@ConfigurationPropertiesScan` participation.
- [x] 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`
- [x] Prove `DISABLED + bindings 0 + provider definitions 0` resolves to
`DISABLED_VERIFIED`, selected binding/card count 0.
- [x] Reject `DISABLED` with bindings or provider resources.
- [x] Reject `ACTIVE` with zero bindings.
- [x] For every binding, require an exact provider, provider destination, and registered operation
catalog for the same destination.
- [x] Derive the `httpclient-static-buffered` card from each current buffered classic profile.
- [x] 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`
- [x] Detach legacy HTTP infrastructure from component/configuration-properties scanning while
preserving direct constructors/factory methods used by forks and existing unit tests.
- [x] Register only canonical configuration, immutable registries, resolver, and inert descriptor
in the composition root.
- [x] 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.
- [x] Assert zero `OutboundHttpClient`, `RestClient`, `OutboundCallExecutor`,
`OutboundHttpShutdownGuard`, `OutboundHttpResilience`, `RetryRegistry`, and
`CircuitBreakerRegistry` beans/resources in the default context.
- [x] Assert contradictory/ACTIVE configurations fail startup before resource construction.
- [x] 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`
- [x] Mark canonical zero-binding as implemented without marking HTTP R2 complete.
- [x] Keep HC5/provider resources/security/real-network qualification explicitly unimplemented.
- [x] Run focused tests:
```bash
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.