Sub-scope 06 (httpclient) service + dynamic + observation + migration — manifest and probes revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5 generatedAt=2026-08-30T05:36:11+00:00 === OWNED FILES === 2af09e541e44e5fe5a7cf24b15136642768a4087 main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/CallScopedDnsPin.java 78 27618ac790d4e0046ae8dc9ccfe822a9ad04adc8 main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/CanonicalTarget.java 41 22074cb132f9d4d512170e12714c4ade7d4b0a20 main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/DefaultDynamicTargetGateway.java 228 b7fcfaa0a7cdc49c6b08dedc00e57d60f45caa69 main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/DynamicCredentialBinding.java 79 ac3fc51793c5fb8b94ae7f9622ef2efa28202343 main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/DynamicTargetGateway.java 21 f321f921eb9a532d0646a693bd708c27900948c5 main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/DynamicTargetPolicy.java 86 f2437231ac5e58c5c4330e42c27d60d785b9245d main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/DynamicTargetPolicyName.java 16 71577ef97db1dcdd53278b6a290917a12332ff2e main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/IpAddressClassifier.java 215 960c7a4f75ed4bb91fa15aca5eba0620fff90ee4 main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/PinnedTarget.java 24 50d4d3bf482d7c01534c9291acdecf395d552858 main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/TargetCanonicalizer.java 112 29a3df649ea8a3a92008e518f495a792d75c51b8 main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/ValidatedDnsResolver.java 89 e43820f9778a041ec21f43f3131b22535b351592 main/java/dev/caskeleton/adapter/outbound/httpclient/migration/MigrationFinding.java 37 bb3563961e27ea83ec9d98066378ffe645d5f7a9 main/java/dev/caskeleton/adapter/outbound/httpclient/migration/RestTemplateInventory.java 37 6975590b25ec9c54b609b38417c3b9ebc4a5ff10 main/java/dev/caskeleton/adapter/outbound/httpclient/migration/RestTemplateInventoryScanner.java 59 c732b6ab9d542765795d0e5762f929010f809e8d main/java/dev/caskeleton/adapter/outbound/httpclient/migration/RestTemplateToRestClientAdapter.java 31 1dbb0bc7d98e76add4e87c26855ea8bd0e8bea8b main/java/dev/caskeleton/adapter/outbound/httpclient/observation/AttemptObservation.java 91 07b76d79376e25d75d9a234128ad41f393b7447d main/java/dev/caskeleton/adapter/outbound/httpclient/observation/HttpClientObservationNames.java 38 3b3fa7a105542ea7a4fa37b704d6c7b801d59337 main/java/dev/caskeleton/adapter/outbound/httpclient/observation/HttpClientTagPolicy.java 48 4577e52c32022a0e22db855e2c1f3ce996e6b236 main/java/dev/caskeleton/adapter/outbound/httpclient/observation/LogicalCallObservation.java 86 8666481f62760563c8879a9aa50925a6c9e149e8 main/java/dev/caskeleton/adapter/outbound/httpclient/observation/SafeHttpLogEvent.java 65 a5e69de9d6450b425396ac9563d2d6bb72dc531f main/java/dev/caskeleton/adapter/outbound/httpclient/observation/SensitiveValueRedactor.java 53 52bb01e25a00172aa0fcde9d27abb494ce115aba main/java/dev/caskeleton/adapter/outbound/httpclient/service/BlockingServiceInvocationHandler.java 52 a6a4b2c442a54d0db9c67f25b67a4d9969fff801 main/java/dev/caskeleton/adapter/outbound/httpclient/service/DefaultHttpServiceRegistry.java 115 c36bc593bf52dc041194e6ee20b2a8a9a939f189 main/java/dev/caskeleton/adapter/outbound/httpclient/service/DefaultReactiveHttpServiceRegistry.java 108 6a755427420edbcef4159b66a5ad65d81ff73176 main/java/dev/caskeleton/adapter/outbound/httpclient/service/HttpClientProfile.java 21 b2f36166a930c990b0389ed1be9923cce7e19dc5 main/java/dev/caskeleton/adapter/outbound/httpclient/service/HttpOperationPolicy.java 33 3b49db43679a3fd95703ce5e599c212820499009 main/java/dev/caskeleton/adapter/outbound/httpclient/service/HttpServiceRegistry.java 17 59929fedf0b1ab68e78c60271dea5a4127a12235 main/java/dev/caskeleton/adapter/outbound/httpclient/service/KernelHttpExchangeAdapter.java 211 7930325d46b5da36e0c87ea60fc917c5bc429044 main/java/dev/caskeleton/adapter/outbound/httpclient/service/OperationContextHolder.java 38 bcad49a3265db6dd3157220f85ce8ad7cdb29d55 main/java/dev/caskeleton/adapter/outbound/httpclient/service/ReactiveHttpServiceRegistry.java 11 935bf7584884f90f86c315d861466dcaf88bcff6 main/java/dev/caskeleton/adapter/outbound/httpclient/service/ReactiveKernelHttpExchangeAdapter.java 272 968873f1b16a0d6fe5dad9068651fce1b020bee4 main/java/dev/caskeleton/adapter/outbound/httpclient/service/ReactiveOperationContext.java 21 20522e681dcae77d02b1a2ec30602ac2ea7c2113 main/java/dev/caskeleton/adapter/outbound/httpclient/service/ReactiveServiceInvocationHandler.java 79 bce1f13e9c22a53e49fc019b930acf4a812a9a3a main/java/dev/caskeleton/adapter/outbound/httpclient/service/ServiceOperationDescriptor.java 32 b7ecaf988db71e1a4f90eb9f5ff3aa654eed3de0 main/java/dev/caskeleton/adapter/outbound/httpclient/service/ServiceOperationDescriptorScanner.java 154 d276cc605f4f92df779c48b847cbaa946788d3ff test/java/dev/caskeleton/adapter/outbound/httpclient/architecture/HttpClientModuleBoundaryTest.java 115 76e10b273255a7e8faf974420802a897fdcf2271 test/java/dev/caskeleton/adapter/outbound/httpclient/architecture/PlatformClasses.java 40 2aa907b1b3f9df7a5beb1094b2a057db7d318efe test/java/dev/caskeleton/adapter/outbound/httpclient/architecture/PublicApiArchitectureTest.java 152 eb356ac8a3a3092902a7caa9cbc09d593167f8b5 test/java/dev/caskeleton/adapter/outbound/httpclient/contract/AllStableTransportsContractTest.java 217 bd864272cb9ba0fe3d330f5bd19b2ef76e6b296d test/java/dev/caskeleton/adapter/outbound/httpclient/contract/FailureInjectionContractTest.java 86 bf64d702c186503c074297bd9a2e13c27a2072b1 test/java/dev/caskeleton/adapter/outbound/httpclient/contract/NegotiatedProtocolContractTest.java 175 8bddf0864197c9b35d50f20fe55b7d761fb68bef test/java/dev/caskeleton/adapter/outbound/httpclient/contract/ResourceLifecycleContractTest.java 42 b14b51f5ffe6151719542b0be41d1abfc77a8858 test/java/dev/caskeleton/adapter/outbound/httpclient/contract/RetrySafetyContractTest.java 15 4aa7e00c81f2f679cfe7a38bb51ec8eba8c55316 test/java/dev/caskeleton/adapter/outbound/httpclient/contract/SecurityContractTest.java 84 12732b6ced283b139cff9db6d0bf3ad7a1e39ff8 test/java/dev/caskeleton/adapter/outbound/httpclient/contract/StatefulUpstreamRetryContractTest.java 170 e795be1532576002788b322c9e7020ffbdd1fe02 test/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/DynamicTargetSecurityTest.java 253 efc598351139295ac9485b5fc5ce5fe473a94697 test/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/TargetCanonicalizerTest.java 76 ac0708d2aefb5465a388847f60583f5d98f8fc50 test/java/dev/caskeleton/adapter/outbound/httpclient/migration/RestTemplateBoundaryTest.java 45 002cfe85746b58db8f5b1835be984426b9702d89 test/java/dev/caskeleton/adapter/outbound/httpclient/migration/RestTemplateToRestClientAdapterTest.java 64 8663d7ee8c483d6a6bd77c2a3d018ac44e92bfe5 test/java/dev/caskeleton/adapter/outbound/httpclient/observation/DeclaredMetricsAreEmittedTest.java 131 470f72a9496f91468355c26b563d36a6e9ff1a19 test/java/dev/caskeleton/adapter/outbound/httpclient/observation/HttpClientTagPolicyTest.java 85 2b4770cd22b6faf5c0a0c1bdaaeb6855f5d9d390 test/java/dev/caskeleton/adapter/outbound/httpclient/service/BlockingHttpServiceRegistryTest.java 76 a9522043a7c32ca58b7c486aa1e1d651f1801c22 test/java/dev/caskeleton/adapter/outbound/httpclient/service/BlockingReactiveSignatureSeparationTest.java 43 7cd7f5e356477c0d95ec5091e83862aa6e673949 test/java/dev/caskeleton/adapter/outbound/httpclient/service/ReactiveHttpServiceRegistryTest.java 89 99cbf7319f1fbfbd56cd687ef18211de2911b3db test/java/dev/caskeleton/adapter/outbound/httpclient/service/ServiceSignatureValidationTest.java 67 ff643ff91f7840c09b3699789d506f995992aa01 test/java/dev/caskeleton/adapter/outbound/httpclient/service/TypedClientPlatformPolicyTest.java 136 main: 35 test: 21 === 8.1 approved 맵의 수명 === $ grep -n 'approved' adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/ValidatedDnsResolver.java 27: * approved five minutes ago is not evidence about the host now, which is the entire premise of 37: private final Map> approved = new ConcurrentHashMap<>(); 58: approved.remove(host); 65: approved.put(host, immutable); 74: public List approvedAddresses(String host) { 75: return approved.getOrDefault(host, List.of()); 79: approved.remove(host); exit=0 $ grep -n 'resolver.forget' -B 3 adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/DefaultDynamicTargetGateway.java 118- } finally { 119- // Discarded at the end of the hop. Retaining it would grow without bound and, worse, 120- // would let a later call reuse an approval that was only ever made for this one. 121: resolver.forget(pinned.target().host()); exit=0 $ git grep -n 'approvedAddresses(' -- 'adapter/outbound/httpclient/src/main' 'app-bootstrap/src/main' | grep -v CallScopedDnsPin | grep -v PinnedTarget adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/dynamic/ValidatedDnsResolver.java:74: public List approvedAddresses(String host) { exit=0 === 8.2 전송이 핀을 통해 해석하는가 === $ grep -n 'CallScopedDnsPin::addressesFor\|ValidatedAddressResolverGroup' -r app-bootstrap/src/main adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/httpclient/HttpClientTransportAutoConfiguration.java:81: return Optional.of(CallScopedDnsPin::addressesFor); adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/reactor/ReactorHttpClientFactory.java:66: AddressResolverGroup resolver = new ValidatedAddressResolverGroup(approvedAddresses.get()); adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/reactor/ValidatedAddressResolverGroup.java:24:public final class ValidatedAddressResolverGroup extends AddressResolverGroup { adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/reactor/ValidatedAddressResolverGroup.java:28: public ValidatedAddressResolverGroup(Function> approvedAddresses) { exit=0 === 8.3 관측 태그 폐쇄성 === $ grep -n 'Set.of\|reject\|ALLOWED' adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/observation/HttpClientTagPolicy.java | head -20 9: *

The policy rejects an unknown tag name instead of accepting it: a metric backend cannot undo a 15: private static final Set ALLOWED = 16: Set.of( 39: return ALLOWED; 43: if (!ALLOWED.contains(name)) { exit=0 $ grep -n 'query\|drop\|redact' adapter/outbound/httpclient/src/main/java/dev/caskeleton/adapter/outbound/httpclient/observation/SensitiveValueRedactor.java | head -12 11: *

Query values are dropped entirely rather than masked per key: an allowlist of "safe" query 44: /** Returns the URI without userinfo, query, or fragment. */ exit=0 === 8.4 아키텍처 test와 계약 lane === $ git ls-files 'adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/architecture' 'adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/contract' | xargs -n1 basename HttpClientModuleBoundaryTest.java PlatformClasses.java PublicApiArchitectureTest.java AllStableTransportsContractTest.java FailureInjectionContractTest.java NegotiatedProtocolContractTest.java ResourceLifecycleContractTest.java RetrySafetyContractTest.java SecurityContractTest.java StatefulUpstreamRetryContractTest.java exit=0 $ git grep -h ' void [a-z]\|@Tag(' -- 'adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/architecture' 'adapter/outbound/httpclient/src/test/java/dev/caskeleton/adapter/outbound/httpclient/contract' | sed 's/^ *//' | sort -u | head -40 @Tag("httpclient-contract") @Tag("httpclient-fault") @Tag("httpclient-security") @Tag("httpclient-spring62-surface") void aResetPeerProducesStableEvidenceRatherThanAGenericFailure() throws Exception { void absoluteUriIsRejectedOnEveryTransport(String transport) throws Exception { void anApacheProfileCannotClaimHttp2() { void connectionsSurviveErrorStatusDecodeFailureAndUnreadStreams() throws Exception { void coreApiDependsOnNothingInsideThePlatform() { void crossOriginRedirectDoesNotForwardCredentials() throws Exception { void doesNotRetryANonIdempotentWriteAgainstTheSameStatefulUpstream() throws Exception { void dynamicTargetsRejectEveryForbiddenAddressClass() { void errorStatusMapsToTheSameStableException(String transport) throws Exception { void everyDocumentedRetryCaseHoldsItsDecision() { void everySelectedBlockingTransportRanEveryContract() { void everySelectedReactiveTransportRanEveryContract() { void everySelectedTransportIsClaimedByExactlyOneContainer() { void honoursRetryAfterAndSucceedsOnTheSecondAttempt() throws Exception { void methodAndTemplateEncodingIsIdentical(String transport) throws Exception { void noProductionPackageDependsOnTheTestkit() { void noPublicMethodHandsOutASpringHttpClient() { void noPublicMethodReturnsANativeEngineClient() { void notSentConnectFailureHasSameStableMetadata(String transport) { void observationVocabularyRejectsHighCardinalityAndSecrets() { void oversizedStreamingResponseIsRejected() throws Exception { void profileDependsOnlyOnTheCoreApi() { void publicApiDoesNotExposeNativeEnginesOrUnsafeBuilders() { void recordedMetersCarryNoUrlOrCredential() throws Exception { void replaysOnceAfterA401AndReResolvesTheCredential() throws Exception { void resilienceOwnsRetryDecisionsWithoutDependingOnTransports() { void springHttpClientsAreConfinedToTheirExecutionPackages() { void stopsAtTheConfiguredAttemptCeilingAgainstAPermanentlyFailingUpstream() throws Exception { void theApacheClassicClientCannotSpeakPriorKnowledgeH2c() throws Exception { void theCoreApiCarriesNoMutableBuilderSurface() { void theExperimentalHttp3PackageIsNotReferencedByStableCode() { void theJdkTransportNegotiatesHttp2WhenTheProfileAsksForIt() throws Exception { void theJdkTransportStaysOnHttp11WhenTheProfileSaysSo() throws Exception { void theReactorTransportNegotiatesHttp2() throws Exception { void theSelectedTransportSetIsExplicit() { void theSpring7ServiceGroupApiIsUsedOnlyInItsOwnPackage() { exit=0