Sub-scope 01 (httpclient) governance + profile/** — manifest and probes
revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5
generatedAt=2026-08-30T05:21:40+00:00

=== OWNED FILES ===
eaeb311707b44e88fdc5914251774db544b64186 CLAUDE.md 79
21139d2ec3ee8edf0ce7c2e71a571da6198b62bc README.md 77
47e011d4cf6a04f4db4ef153653a4049f4d5a3f2 build.gradle 258
5f186c01a45409f963e17bb199a6b14ef9e0a0a9 gradle.lockfile 249
a8f810ca166f416197ff199b4475f8d68fe7c8e1 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/AuthenticationSettings.java 42
9d4e34483521fd54a7caf07a448758d8131fb142 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/AuthenticationType.java 21
b74ee2604e3a001be5e9b480f5db9f9e2b81e08e src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientApiType.java 7
d35151bdf7a319646af8709fdde7b2719479c257 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientMode.java 9
a24610e1639c6956ae02b86465e8d58a80785d70 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientObservabilitySettings.java 13
a18f25310f7faf710ea6485bd45336bfded15bff src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientProfile.java 75
6d1ea925b16d7da65dc109d64d3447f4b80f17fa src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientProfileValidator.java 291
4b97c29f7a8b288f43753840e1a1b9ac7a2a92d1 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientProfileViolation.java 24
0c7110af7e768916828f0fb4687bcb11325be6fe src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientRuntime.java 102
f2511df6cdfeeade638e54085713c7a94ad56bcd src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientRuntimeFactory.java 13
6dcdc1770ea903e16a42179f76c82b1e1a861494 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientRuntimeLease.java 33
09bb0b65b62637b83944ba7f30dd6b6f95efc333 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientRuntimeRegistry.java 187
8c64ba3c861e2215170b7bbcff0c9c830bf8f3b5 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientRuntimeState.java 11
0e98fb9fae7439d6952456cf76fe838aa48475c8 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/HttpProtocol.java 9
f40341f55e85c665db394d0342c8b3940c55234d src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/JitterStrategy.java 8
c869e6d94ce77e53a2c37d9d2c495271276cdbce src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/PoolSettings.java 39
8e1d299d96b52dc43482e580394326100eb34f90 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ProtocolIntent.java 61
5c7380a6490b379f4411db1e5879c654511d489a src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ProxySettings.java 39
cbdba40b3977eb78e5603330fee53c85e8fb8fe1 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ProxyType.java 7
dde509058da2af01c7b76f4c9a8811e6a378c821 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/RedirectSettings.java 20
f756c6f4845e39ab55fd320fdaa58a0599e85707 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/RequestLimits.java 11
400a95a2af281c0cb4ab65ab7aae28c0437053a7 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ResponseLimits.java 38
bb3fb5481dbd80256d42aeacdba5984c3fb13803 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/RetryAfterPolicy.java 11
2f6905695d191e43bf049753ca16f87f12524e4d src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/RetrySettings.java 57
da3ddc8be6df41f420a2f32e5f9a50c2fd9b8121 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/RuntimeEnvironment.java 16
283544ae6d50a9339e6e94d6908d68987e20bae8 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/RuntimeGeneration.java 15
b9502e98f2c2817becaef6929b496c8a9f45a095 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/TimeoutSettings.java 46
e44285231db61d50346283e9114ca66969973fbc src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/TlsSettings.java 51
93a3febddb367dc9ee180dae11f7f9493e607af9 src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/TransportType.java 15
8a6180116432266d97928b847d626395121e8f51 src/test/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientProfileValidatorTest.java 106
6a992e4043922dcdb839479ab794e015d4c161b4 src/test/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientRuntimeRegistryTest.java 64

main: 29  test: 2  governance: 4
=== 8.1 reachability: validator와 registry가 실제로 배선되는가 ===
$ git grep -n 'ClientProfileValidator' -- . | grep -v 'profile/ClientProfileValidator.java'
adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/HttpProtocol.java:7:  /** Experimental. Rejected on Stable profiles by {@link ClientProfileValidator}. */
adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/TlsSettings.java:15: * {@code ClientProfileValidator} and {@code TlsPolicyValidator} both fail closed on them.
adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/TransportType.java:13:  /** Local test only. Rejected in production by {@link ClientProfileValidator}. */
adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientProfileValidatorTest.java:11:class ClientProfileValidatorTest {
adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientProfileValidatorTest.java:13:  private final ClientProfileValidator validator = new ClientProfileValidator();
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientStartupValidator.java:9:import dev.caskeleton.adapter.outbound.httpclient.profile.ClientProfileValidator;
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientStartupValidator.java:37:  private final ClientProfileValidator profileValidator = new ClientProfileValidator();
exit=0

$ git grep -ln 'ClientRuntimeRegistry' -- 'adapter/outbound/httpclient/src/main' 'app-bootstrap/src/main'
adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/DefaultDynamicTargetGateway.java
adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientRuntimeRegistry.java
adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/BlockingStreamingGateway.java
adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/restclient/DefaultGenericHttpGateway.java
adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/security/TlsRuntimeRotationCoordinator.java
adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/service/DefaultHttpServiceRegistry.java
adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/service/DefaultReactiveHttpServiceRegistry.java
adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/DefaultReactiveHttpGateway.java
adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/DefaultReactiveSseGateway.java
adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/webclient/ReactiveStreamingGateway.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/DynamicTargetAutoConfiguration.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientActuatorEndpoint.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientManagementAutoConfiguration.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientProfileAutoConfiguration.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpServiceClientAutoConfiguration.java
exit=0

$ git ls-files 'adapter/outbound/httpclient/src/main/resources' 2>/dev/null; echo 'resources: none tracked'
resources: none tracked
exit=0

=== 8.1b app-bootstrap가 이 leaf를 어떻게 조립하는가 ===
$ git grep -ln 'dev.caskeleton.adapter.outbound.httpclient' -- 'app-bootstrap/src/main' | head -20
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/DynamicTargetAutoConfiguration.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientActuatorEndpoint.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientAuthenticationAutoConfiguration.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientManagementAutoConfiguration.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientObservationAutoConfiguration.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientProfileAutoConfiguration.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientProfileFactory.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientResilienceAutoConfiguration.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientSecurityAutoConfiguration.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientStartupValidator.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientTransportAutoConfiguration.java
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpServiceClientAutoConfiguration.java
exit=0

=== 8.2 위반 코드 집합과 test 대조 ===
$ grep -oE 'violation\("[A-Z0-9_]+"' adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientProfileValidator.java | sed 's/violation("//;s/"//' | sort -u
ALLOWED_HOST_MISMATCH
ALLOWED_PORT_MISMATCH
API_KEY_HEADER_NAME_REQUIRED
BASE_URL_QUERY_FORBIDDEN
BASE_URL_USERINFO_FORBIDDEN
BODY_LOGGING_FORBIDDEN
DNS_TIMEOUT_UNSUPPORTED
DYNAMIC_BASE_URL_REQUIRED
DYNAMIC_DEFAULT_CREDENTIAL_FORBIDDEN
DYNAMIC_TARGET_PROXY_UNSUPPORTED
DYNAMIC_TARGET_TRANSPORT_UNSUPPORTED
FULL_URL_RECORDING_FORBIDDEN
HOSTNAME_VERIFICATION_REQUIRED
HTTP2_REQUIRED_TRANSPORT_UNSUPPORTED
HTTP3_STABLE_FORBIDDEN
INVALID_TIMEOUT_BUDGET
JDK_FINE_GRAINED_POOL_UNSUPPORTED
MISSING_PRODUCTION_SETTING
OAUTH2_REGISTRATION_REQUIRED
PLAINTEXT_FALLBACK_FORBIDDEN
PLAINTEXT_PRODUCTION_TARGET
POOL_ROUTE_EXCEEDS_TOTAL
PRODUCTION_SIMPLE_FACTORY_FORBIDDEN
PROXY_CREDENTIAL_UNSUPPORTED
REACTIVE_REDIRECT_UNSUPPORTED
REDIRECT_CROSS_ORIGIN_CREDENTIAL_POLICY_REQUIRED
REDIRECT_POLICY_INVALID
RESPONSE_HARD_MAXIMUM_EXCEEDED
RETRY_BACKOFF_REQUIRED
RETRY_POLICY_CONTRADICTS_ATTEMPTS
TLS_PROTOCOL_FORBIDDEN
TLS_PROTOCOL_SET_REQUIRED
TRUSTED_BASE_URL_REQUIRED
TRUST_ALL_FORBIDDEN
exit=0

$ grep -oE 'violation\("[A-Z0-9_]+"' adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientProfileValidator.java | sed 's/violation("//;s/"//' | sort -u | wc -l
34
exit=0

$ git grep -ohE '"[A-Z0-9_]{6,}"' -- 'adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/profile' | tr -d '"' | sort -u
BASE_URL_QUERY_FORBIDDEN
BASE_URL_USERINFO_FORBIDDEN
DYNAMIC_DEFAULT_CREDENTIAL_FORBIDDEN
HOSTNAME_VERIFICATION_REQUIRED
HTTP3_STABLE_FORBIDDEN
INVALID_TIMEOUT_BUDGET
JDK_FINE_GRAINED_POOL_UNSUPPORTED
PLAINTEXT_FALLBACK_FORBIDDEN
PLAINTEXT_PRODUCTION_TARGET
PRODUCTION_SIMPLE_FACTORY_FORBIDDEN
TRUST_ALL_FORBIDDEN
exit=0

=== 8.3 close() 순서: 실패 시 scheduler 종료에 도달하는가 ===
$ sed -n '119,160p' adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientRuntimeRegistry.java
  @Override
  public void close() {
    List<ClientRuntime> all = new ArrayList<>();
    runtimes.values().forEach(holder -> all.add(holder.get()));
    // Retired-but-still-draining generations are closed too; they used to survive registry
    // shutdown entirely.
    all.addAll(retired);
    // Every runtime is closed even when one refuses. forEach stopped at the first exception, so a
    // single misbehaving pool left every remaining connection, thread and socket open — shutdown
    // leaked more the worse the failure was.
    RuntimeException firstFailure = null;
    for (ClientRuntime runtime : all) {
      try {
        runtime.forceClose();
      } catch (RuntimeException failure) {
        if (firstFailure == null) {
          firstFailure = failure;
        } else {
          firstFailure.addSuppressed(failure);
        }
      }
    }
    retired.clear();
    runtimes.clear();
    if (firstFailure != null) {
      throw firstFailure;
    }
    ScheduledExecutorService scheduler = drainScheduler.getAndSet(null);
    if (scheduler != null) {
      // Await termination: a registry that returns while its drain thread is still alive would
      // leak a thread per rotation cycle, which the resource-bound suite exists to catch.
      scheduler.shutdownNow();
      try {
        if (!scheduler.awaitTermination(SHUTDOWN_AWAIT_MILLIS, TimeUnit.MILLISECONDS)) {
          throw new IllegalStateException("http client drain scheduler did not terminate");
        }
      } catch (InterruptedException interrupted) {
        Thread.currentThread().interrupt();
      }
    }
  }

exit=0

=== 8.4 test 목록과 이름 ===
$ git ls-files 'adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/profile' | xargs -n1 basename
ClientProfileValidatorTest.java
ClientRuntimeRegistryTest.java
exit=0

$ git grep -h '  void [a-z]' -- 'adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/profile' | sed 's/^ *//'
void rejectsPlainHttpInProduction() {
void rejectsDynamicCredentialInheritance() {
void rejectsTotalTimeoutShorterThanConnectBudget() {
void rejectsUnsafeTlsConfiguration() {
void rejectsSimpleFactoryAndUnacknowledgedHttp3AndJdkRoutePool() {
void rejectsBaseUrlUserInfoAndQuery() {
void violationOrderIsDeterministic() {
void acceptsAFullyDeclaredProductionProfile() {
void newCallsUseNewGenerationWhileOldCallDrains() {
void drainingRuntimeRefusesNewAttempts() {
void closingTheRegistryReleasesEveryGenerationAndLeavesNoThread() {
exit=0


=== 8.3b POOL_ROUTE_EXCEEDS_TOTAL 도달 가능성 ===
$ grep -n 'maxConnectionsPerRoute > maxTotalConnections' -A 2 adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/PoolSettings.java
35:    if (maxConnectionsPerRoute > maxTotalConnections) {
36-      throw new IllegalArgumentException("per-route pool must not exceed the total pool");
37-    }
exit=0

$ grep -n 'POOL_ROUTE_EXCEEDS_TOTAL' -B 4 adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientProfileValidator.java
191-    }
192-    if (profile.pool().maxConnectionsPerRoute() > profile.pool().maxTotalConnections()) {
193-      // A per-route ceiling above the total is incoherent, and on Reactor — where the per-route
194-      // knob is the only one that exists — it silently becomes the effective limit.
195:      out.add(violation("POOL_ROUTE_EXCEEDS_TOTAL", profile, "pool.max-connections-per-route"));
exit=0

$ git grep -rn 'new PoolSettings(' -- 'adapter/outbound/httpclient/src/main' 'app-bootstrap/src/main' | head
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientProfileFactory.java:83:    return new PoolSettings(
exit=0

=== 8.4b 위반 코드 34종 중 test가 이름으로 잡는 것 ===
$ for c in $(grep -oE 'violation\("[A-Z0-9_]+"' adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/profile/ClientProfileValidator.java | sed 's/violation("//;s/"//' | sort -u); do n=$(git grep -l "$c" -- '*/src/test/*' '*/src/testkit/*' | wc -l); printf '%-45s test=%s\n' "$c" "$n"; done
ALLOWED_HOST_MISMATCH                         test=0
ALLOWED_PORT_MISMATCH                         test=0
API_KEY_HEADER_NAME_REQUIRED                  test=0
BASE_URL_QUERY_FORBIDDEN                      test=1
BASE_URL_USERINFO_FORBIDDEN                   test=1
BODY_LOGGING_FORBIDDEN                        test=0
DNS_TIMEOUT_UNSUPPORTED                       test=0
DYNAMIC_BASE_URL_REQUIRED                     test=0
DYNAMIC_DEFAULT_CREDENTIAL_FORBIDDEN          test=2
DYNAMIC_TARGET_PROXY_UNSUPPORTED              test=0
DYNAMIC_TARGET_TRANSPORT_UNSUPPORTED          test=0
FULL_URL_RECORDING_FORBIDDEN                  test=0
HOSTNAME_VERIFICATION_REQUIRED                test=2
HTTP2_REQUIRED_TRANSPORT_UNSUPPORTED          test=0
HTTP3_STABLE_FORBIDDEN                        test=2
INVALID_TIMEOUT_BUDGET                        test=1
JDK_FINE_GRAINED_POOL_UNSUPPORTED             test=1
MISSING_PRODUCTION_SETTING                    test=0
OAUTH2_REGISTRATION_REQUIRED                  test=0
PLAINTEXT_FALLBACK_FORBIDDEN                  test=2
PLAINTEXT_PRODUCTION_TARGET                   test=2
POOL_ROUTE_EXCEEDS_TOTAL                      test=0
PRODUCTION_SIMPLE_FACTORY_FORBIDDEN           test=2
PROXY_CREDENTIAL_UNSUPPORTED                  test=0
REACTIVE_REDIRECT_UNSUPPORTED                 test=0
REDIRECT_CROSS_ORIGIN_CREDENTIAL_POLICY_REQUIRED test=0
REDIRECT_POLICY_INVALID                       test=0
RESPONSE_HARD_MAXIMUM_EXCEEDED                test=0
RETRY_BACKOFF_REQUIRED                        test=0
RETRY_POLICY_CONTRADICTS_ATTEMPTS             test=0
TLS_PROTOCOL_FORBIDDEN                        test=1
TLS_PROTOCOL_SET_REQUIRED                     test=0
TRUSTED_BASE_URL_REQUIRED                     test=0
TRUST_ALL_FORBIDDEN                           test=3
exit=0

