Sub-scope 01 (cache-redis) governance + sdk/config — manifest and negative-space probes revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5 generatedAt=2026-08-30T03:59:48+00:00 cwd=/shared/codebase/clean-architecture-backend-template/src === OWNED FILES === d7d9299d8b8d61386d14f09d8c50da1dad758efa CLAUDE.md 143 8598f863777600267efdac00e5624d96d6ceec8f README.md 381 99c8f5bede105ee16ac9312c9aee055c16900076 build.gradle 202 062d16a37189b5de4bae45f3a05424504efda198 gradle.lockfile 164 e4b23adfdf4fe19b64c9d29c58bdd4d721fceba1 src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/ConfiguredRedisPermitVerifier.java 94 08397249ba133ab758419f95af9c52ce9ccd17a9 src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/ConfiguredRedisPolicyAuthority.java 106 c114b289e2da0b2afd60104af8c50f1561d070b6 src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/GrantedAdvancedOperationPermit.java 24 d474a8d29be05c0e6e7eb836736ebd3625936012 src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/GrantedMultiKeyPermit.java 21 c4c3b611267c35a0721413acba22cc773914bc06 src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/GrantedPersistentKeyPermit.java 21 0bb89c573b6c80d71f0f9122374e7639acd9b57b src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbe.java 176 5c008151853a73ff417482f803602ba6f6418b61 src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCorrectnessRoles.java 62 929a59fa7035c717447b72eac36cdeb57c2e0513 src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCredentialResolver.java 125 5e1ec779b058125188a7e4b86150935f0df37a52 src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisHealthContributor.java 88 a699afb72b41717d121dcff3778555da2ab18ea1 src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkAutoConfiguration.java 397 2f577f0c64e7d108b9e7d477ccc61010e3da852b src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettings.java 959 9ac874da2ffd3f901e168aaa3c20e019ae9922bb src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbe.java 142 47656d4826960bf5b4717d44569527a3ead037cf src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/LiveRedisCompositionTest.java 176 10a77ad0f8096326079ae25358863840616084b8 src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/LiveRedisTlsTest.java 141 3a266c797630d7cf8c5e917f759c8edbbf4ba675 src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbeTest.java 158 e3ff2763675b302239deee9fbb6cb31d0b526a94 src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisPermitProvenanceTest.java 87 6e97086762eb93705c72b009d970002dbd882fd8 src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkAutoConfigurationTest.java 447 6b576bbf04cee7791e7c688c9fb910e39935d24d src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettingsTest.java 201 8bea0f7148c054e816fe876ff4731b3961933a32 src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java 145 ebb0ed7ab8900c0007582e96351ff8bbfd7bb0ad src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RequiredWhenIsEnforcedTest.java 152 223a63b5cefb8be4169e068f5f6404e16a7c2a7f src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 1 1f51d1352a6a3f515b3d1cf4d40aed4f120d42de src/main/resources/redis-sdk/redis-command-policy.yml 1406 === 8.4 README readiness 표 vs 실제 소스 === $ sed -n '23,41p' adapter/outbound/cache-redis/README.md | Capability | API 구현 | Spring composition 구현 | 실서버 qualification | | --- | --- | --- | --- | | Redis SDK typed API (`…cache.redis.sdk`) | 있음 | settings bind + validate 까지만 | 없음 | | Topology client / connection lifecycle | 없음 | 없음 | 없음 | | cache / session / idempotency / rate limit / lease semantic port | 없음 | 없음 | 없음 | | role-aware health·readiness contributor | 없음 | 없음 | 없음 | 즉 현재 `APP_REDIS_ENABLED=true`가 하는 일은 `RedisSdkSettings`를 bind하고 cross-field 규칙을 fail-fast로 검증하는 것까지다. client, connection, gateway, semantic adapter, health contributor는 아직 조립되지 않는다. 남은 단계와 순서는 `docs/superpowers/plans/2026-08-10-redis-optionality-and-composition.md`에 있다. readiness registry에도 `selected` card가 없으므로 Redis R2 release claim은 없다. 아래 절들은 이전 세대 semantic adapter 세트의 설계 결정을 기록한 것이며, 그 코드는 현재 이 leaf에 없다. 복구 범위는 위 plan의 Phase E가 소유한다. 모듈은 Lettuce connection lifecycle, finite command timeout, reconnect replay 차단, finite request queue/admission, positive/negative TTL, absolute soft/hard expiry, deterministic bounded TTL jitter, digest-protected v2 binary exit=0 --- 'Topology client / connection lifecycle: 없음' 대조 --- $ git ls-files 'adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/connection' | xargs wc -l 75 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/connection/RedisConnectionKind.java 28 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/connection/RedisConnectionLease.java 142 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/connection/RedisConnectionRegistry.java 32 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/connection/RedisCredentialRole.java 44 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/connection/RedisLease.java 83 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/connection/RedisRuntimeClient.java 316 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/connection/RedisRuntimeOwner.java 600 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/connection/RedisTopologyClientFactory.java 153 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/connection/SentinelFailoverObserver.java 1473 total exit=0 --- 'semantic port: 없음' / '그 코드는 현재 이 leaf에 없다' 대조 --- $ git ls-files 'adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/cache' 'adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/idempotency' 'adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/lease' 'adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/ratelimit' 'adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/realtime' 'adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/keyspace' | xargs wc -l 213 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/cache/CacheEnvelope.java 428 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/cache/RedisCacheRegionAdapter.java 306 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/idempotency/IdempotencyScripts.java 529 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/idempotency/RedisIdempotencyStoreAdapter.java 106 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/keyspace/CapabilityKeyspace.java 203 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/lease/LeaseScripts.java 403 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/lease/RedisDistributedLeaseAdapter.java 49 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/ratelimit/RateLimitKeys.java 280 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/ratelimit/RateLimitScripts.java 187 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/ratelimit/RedisEdgeRateLimitAdapter.java 81 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/realtime/RealtimeKeys.java 301 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/realtime/RedisConnectionRegistryAdapter.java 133 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/realtime/RedisEphemeralFanoutAdapter.java 76 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/realtime/RegistrationCodec.java 3295 total exit=0 --- 'role-aware health contributor: 없음' 대조 --- $ git ls-files 'adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config' | grep -i 'health\|role' | xargs wc -l 62 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCorrectnessRoles.java 88 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisHealthContributor.java 150 total exit=0 === 8.4b build.gradle의 'Zero imports' 주장 3건 대조 === $ sed -n '6,16p;33,39p' adapter/outbound/cache-redis/build.gradle dependencies { // Registered edges the semantic port adapters need. The SDK itself imports nothing from them // today (0 imports across main source) — the semantic cache/session/idempotency/rate-limit // adapters that did were removed and are restored by Phase E of // docs/superpowers/plans/2026-08-10-redis-optionality-and-composition.md. They stay declared // because that restoration is the module's stated responsibility, not because anything here // compiles against them. implementation project(':application-core') implementation project(':shared-contract') implementation project(':adapter:outbound:support') // Deliberately absent: // org.springframework.data:spring-data-redis — the SDK owns its own typed API and command // policy on purpose; routing through Spring Data would reintroduce the untyped, unguarded // command surface the catalog exists to prevent. Zero imports. // io.micrometer:micrometer-core — observation leaves this leaf as RedisObservation through a // Consumer sink; binding it to a meter registry belongs to the composition root, not here. // Zero imports. exit=0 --- application-core / shared-contract / support import 실측 --- $ git grep -c 'import dev.caskeleton.application\.' -- 'adapter/outbound/cache-redis/src/main' | head -20 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/cache/RedisCacheRegionAdapter.java:9 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/idempotency/RedisIdempotencyStoreAdapter.java:18 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/lease/RedisDistributedLeaseAdapter.java:10 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/realtime/RealtimeKeys.java:2 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/realtime/RedisConnectionRegistryAdapter.java:5 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/realtime/RedisEphemeralFanoutAdapter.java:3 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/realtime/RegistrationCodec.java:4 exit=0 $ git grep -l 'import dev.caskeleton.shared\.' -- 'adapter/outbound/cache-redis/src/main' | head -20 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/ratelimit/RateLimitKeys.java adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/ratelimit/RateLimitScripts.java adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/ratelimit/RedisEdgeRateLimitAdapter.java exit=0 $ git grep -l 'import dev.caskeleton.adapter.outbound.support' -- 'adapter/outbound/cache-redis/src/main' | head exit=0 --- spring-data-redis / micrometer import 실측 --- $ git grep -c 'org.springframework.data.redis\|io.micrometer' -- 'adapter/outbound/cache-redis/src/main' exit=1 === 8.1 조립: auto-configuration이 실제로 만드는 bean === $ cat adapter/outbound/cache-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports dev.caskeleton.adapter.outbound.cache.redis.sdk.config.RedisSdkAutoConfiguration exit=0 $ grep -n '@Bean\|@Conditional\|class \|record ' adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkAutoConfiguration.java 35: *
{@code app.redis.enabled} is the whole switch. While it is false this class contributes
54:@ConditionalOnProperty(prefix = "app.redis", name = "enabled", havingValue = "true")
55:// Registers the binding post-processor that populates the @ConfigurationProperties @Bean below.
59:public class RedisSdkAutoConfiguration {
83: @Bean
101: @Bean
156: @Bean
226: @Bean
273: @Bean(destroyMethod = "close")
297: @Bean(RedisCorrectnessRoles.OPTIONAL_HEALTH_CONTRIBUTOR)
324: @Bean(RedisCorrectnessRoles.REQUIRED_HEALTH_CONTRIBUTOR)
325: @Conditional(RedisCorrectnessRoleBound.class)
344: static final class RedisCorrectnessRoleBound implements Condition {
364: public record RedisResolvedCredentials(
391: public record RedisSdkSettingsValidation(List Package private on purpose: application code can implement the public interface, but it cannot
* construct this type, and the verifier checks the concrete type as well as the signature.
*
* @param policyName the approved policy name
* @param issuerId identity of the issuing authority instance
* @param signature signature the issuing authority computed over the policy name
*/
record GrantedAdvancedOperationPermit(String policyName, String issuerId, String signature)
implements AdvancedOperationPermit {
GrantedAdvancedOperationPermit {
Objects.requireNonNull(policyName, "policyName must be non-null");
Objects.requireNonNull(issuerId, "issuerId must be non-null");
Objects.requireNonNull(signature, "signature must be non-null");
}
}
package dev.caskeleton.adapter.outbound.cache.redis.sdk.config;
import dev.caskeleton.adapter.outbound.cache.redis.sdk.api.command.PersistentKeyPermit;
import java.util.Objects;
/**
* The only persistent-key permit implementation the verifier accepts.
*
* @param policyName the approved policy name
* @param issuerId identity of the issuing authority instance
* @param signature signature the issuing authority computed over the policy name
*/
record GrantedPersistentKeyPermit(String policyName, String issuerId, String signature)
implements PersistentKeyPermit {
GrantedPersistentKeyPermit {
Objects.requireNonNull(policyName, "policyName must be non-null");
Objects.requireNonNull(issuerId, "issuerId must be non-null");
Objects.requireNonNull(signature, "signature must be non-null");
}
}
package dev.caskeleton.adapter.outbound.cache.redis.sdk.config;
import dev.caskeleton.adapter.outbound.cache.redis.sdk.api.command.MultiKeyPermit;
import java.util.Objects;
/**
* The only multi-key permit implementation the verifier accepts.
*
* @param policyName the approved policy name
* @param issuerId identity of the issuing authority instance
* @param signature signature the issuing authority computed over the policy name
*/
record GrantedMultiKeyPermit(String policyName, String issuerId, String signature)
implements MultiKeyPermit {
GrantedMultiKeyPermit {
Objects.requireNonNull(policyName, "policyName must be non-null");
Objects.requireNonNull(issuerId, "issuerId must be non-null");
Objects.requireNonNull(signature, "signature must be non-null");
}
}
exit=0
=== 8.4c config test 목록 ===
$ git ls-files 'adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config' | xargs -n1 basename
LiveRedisCompositionTest.java
LiveRedisTlsTest.java
RedisCapabilityProbeTest.java
RedisPermitProvenanceTest.java
RedisSdkAutoConfigurationTest.java
RedisSdkSettingsTest.java
RedisStartupProbeTest.java
RequiredWhenIsEnforcedTest.java
exit=0
$ git grep -h ' void [a-z]' -- 'adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config' | sed 's/^ *//' | head -60
void aWrongPasswordIsRefused() throws Exception {
void theModeProducesOneMatchingClient() {
void aLeaseReachesTheServer() throws Exception {
void theOptionalContributorReportsUp() {
void closingTheContextTearsEverythingDown() {
void aFilesystemTrustReferenceWorks() {
void aClasspathTrustReferenceWorks() throws IOException {
void unreadableTrustMaterialFailsAtStartup() {
void plaintextAgainstATlsOnlyServerFails() {
void redisSevenTwoHasNoHashFieldExpiration() {
void redisSevenFourGainsHashFieldExpiration() {
void aNewEnoughVersionWithoutTheCommandIsNotACapability() {
void anExplicitlyEnabledCapabilityThatIsAbsentFailsStartup() {
void aServerBelowTheBaselineFailsStartup() {
void clusterWithANonZeroDatabaseFailsStartup() {
void refusesAReplicatedDeploymentThatCannotKeepTheWritesItAcknowledges() {
void acceptsAReplicatedDeploymentWithAWriteGuarantee() {
void rejectsAReplicaCountWithNoLagBound() {
void allowsTheLossOnlyWhenTheDeploymentDeclaredIt() {
void doesNotRequireAWriteGuaranteeFromStandalone() {
void acceptsAPermitTheAuthorityIssued() {
void rejectsAPermitTheCallerImplementedItself() {
void rejectsAPermitIssuedForADifferentPolicy() {
void rejectsAPermitIssuedByAnotherAuthorityInstance() {
void refusesToIssueAPolicyConfigurationDidNotEnable() {
void aPermitCarriesNoAuthorityMaterialInItsPolicyName() {
void absentSwitchRegistersNothing() {
void disabledRegistersNothing() {
void disabledIgnoresMalformedRedisConfiguration() {
void disabledNeverAsksForASecretOrAConnection() {
void enabledResolvesEachConfiguredRoleOnce() {
void enabledBindsSettings() {
void enabledRejectsClusterWithANonZeroDatabase() {
void enabledRejectsAnUnboundedBlock() {
void enabledRejectsARawGatewayWithoutAnAllowlist() {
void enabledRejectsAMissingRawAllowlistResource() {
void enabledAcceptsAReadableRawAllowlistResource() {
void standaloneWithSeveralNodesIsRefused() {
void sentinelWithoutAMasterNameIsRefused() {
void enabledWithoutAnApplicationCredentialIsRefused() {
void anonymousAccessCanBeDeclared() {
void configuredAccountsAreResolvedPerRole() {
void anUnresolvableCredentialReferenceFailsAtStartup() {
void aLiteralCredentialIsRefused() {
void clusterBuildsAClusterClient() {
void theRuntimeOwnerFollowsTheContext() {
void enabledRejectsAnAdminPlaneWithoutItsOwnCredential() {
void clusterRejectsDatabaseOtherThanZero() {
void standaloneAcceptsANonZeroDatabase() {
void namespaceTokensAreValidatedAtStartup() {
void aFastTimeoutAboveTheGuardrailWarnsAndFarAboveItFails() {
void blockingMustNeverBeUnbounded() {
void theRawGatewayRequiresAnAllowlistAndItsOwnCredential() {
void theAdminPlaneRequiresItsOwnCredential() {
void aClientCertificateWithoutItsKeyIsRefusedAtStartup() {
void oneWayTlsNeedsNoClientCertificateAndNoTrustMaterial() {
void advancedPoliciesCannotBeConfiguredWhileAdvancedOperationsAreDisabled() {
void defaultsMatchTheDesignGuardrails() {
void authenticationIsRequiredUnlessAnonymousIsDeclared() {
void aSingleAccountDeploymentIsToldThatScriptingRunsAsTheApplicationAccount() {
exit=0
=== 8.1d reachability: startup probe / capability probe / permit authority ===
$ git grep -n 'RedisStartupProbe\|RedisCapabilityProbe' -- . | grep -v 'sdk/config/RedisStartupProbe.java' | grep -v 'sdk/config/RedisCapabilityProbe.java'
adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettings.java:888: * signal exists for it; see {@link RedisCapabilityProbe#requireWriteDurability}.
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbeTest.java:17:class RedisCapabilityProbeTest {
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbeTest.java:19: private final RedisCapabilityProbe probe = new RedisCapabilityProbe();
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbeTest.java:28: RedisCapabilityProbeTest::everyCommand,
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbeTest.java:42: RedisCapabilityProbeTest::everyCommand,
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbeTest.java:86: RedisCapabilityProbeTest::everyCommand,
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbeTest.java:100: RedisCapabilityProbeTest::everyCommand,
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java:16:class RedisStartupProbeTest {
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java:18: private final RedisStartupProbe probe = new RedisStartupProbe(new RedisCapabilityProbe());
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java:53: RedisStartupProbe.ServerFacts.from(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java:71: RedisStartupProbe.ServerFacts.from(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java:85: RedisStartupProbe.ServerFacts.from(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java:99: RedisStartupProbe.ServerFacts.from(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java:113: RedisStartupProbe.ServerFacts.from(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java:124: RedisStartupProbe.ServerFacts.from(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java:139: RedisStartupProbe.ServerFacts.from(
exit=0
$ git grep -n 'ConfiguredRedisPolicyAuthority\|ConfiguredRedisPermitVerifier' -- . | grep -v 'sdk/config/ConfiguredRedis'
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisPermitProvenanceTest.java:17: private final ConfiguredRedisPolicyAuthority authority =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisPermitProvenanceTest.java:18: new ConfiguredRedisPolicyAuthority(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisPermitProvenanceTest.java:21: private final ConfiguredRedisPermitVerifier verifier =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisPermitProvenanceTest.java:22: new ConfiguredRedisPermitVerifier(authority, RedisDeploymentMode.STANDALONE);
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisPermitProvenanceTest.java:64: ConfiguredRedisPolicyAuthority other =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisPermitProvenanceTest.java:65: new ConfiguredRedisPolicyAuthority(List.of("collection-full-read"));
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/command/CommandPolicyGuardTest.java:23:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.ConfiguredRedisPermitVerifier;
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/command/CommandPolicyGuardTest.java:24:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.ConfiguredRedisPolicyAuthority;
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/command/CommandPolicyGuardTest.java:39: private final ConfiguredRedisPolicyAuthority authority =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/command/CommandPolicyGuardTest.java:40: new ConfiguredRedisPolicyAuthority(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/command/CommandPolicyGuardTest.java:266: new ConfiguredRedisPermitVerifier(authority, mode),
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/command/ObservationIsolationTest.java:18:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.ConfiguredRedisPermitVerifier;
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/command/ObservationIsolationTest.java:19:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.ConfiguredRedisPolicyAuthority;
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/command/ObservationIsolationTest.java:43: private final ConfiguredRedisPolicyAuthority authority =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/command/ObservationIsolationTest.java:44: new ConfiguredRedisPolicyAuthority(List.of());
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/command/ObservationIsolationTest.java:49: new ConfiguredRedisPermitVerifier(authority, RedisDeploymentMode.STANDALONE),
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/LiveRedisOperationsFixture.java:12:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.ConfiguredRedisPermitVerifier;
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/LiveRedisOperationsFixture.java:13:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.ConfiguredRedisPolicyAuthority;
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/LiveRedisOperationsFixture.java:67: final ConfiguredRedisPolicyAuthority authority =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/LiveRedisOperationsFixture.java:68: new ConfiguredRedisPolicyAuthority(ENABLED_POLICIES);
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/LiveRedisOperationsFixture.java:123: ConfiguredRedisPermitVerifier verifier =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/LiveRedisOperationsFixture.java:124: new ConfiguredRedisPermitVerifier(authority, endpoint.mode());
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisOperationsFixture.java:12:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.ConfiguredRedisPermitVerifier;
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisOperationsFixture.java:13:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.ConfiguredRedisPolicyAuthority;
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisOperationsFixture.java:67: final ConfiguredRedisPolicyAuthority authority =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisOperationsFixture.java:68: new ConfiguredRedisPolicyAuthority(ENABLED_POLICIES);
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisOperationsFixture.java:149: ConfiguredRedisPermitVerifier verifier =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisOperationsFixture.java:150: new ConfiguredRedisPermitVerifier(authority, RedisDeploymentMode.STANDALONE);
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisTransactionContractTest.java:17:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.ConfiguredRedisPermitVerifier;
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisTransactionContractTest.java:18:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.ConfiguredRedisPolicyAuthority;
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisTransactionContractTest.java:58: private final ConfiguredRedisPolicyAuthority authority =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisTransactionContractTest.java:59: new ConfiguredRedisPolicyAuthority(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisTransactionContractTest.java:84: ConfiguredRedisPermitVerifier verifier =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisTransactionContractTest.java:85: new ConfiguredRedisPermitVerifier(authority, RedisDeploymentMode.STANDALONE);
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisTransactionSlotContractTest.java:18:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.ConfiguredRedisPermitVerifier;
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisTransactionSlotContractTest.java:19:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.ConfiguredRedisPolicyAuthority;
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisTransactionSlotContractTest.java:63: private final ConfiguredRedisPolicyAuthority authority =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisTransactionSlotContractTest.java:64: new ConfiguredRedisPolicyAuthority(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisTransactionSlotContractTest.java:78: ConfiguredRedisPermitVerifier verifier =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/operations/RedisTransactionSlotContractTest.java:79: new ConfiguredRedisPermitVerifier(authority, RedisDeploymentMode.CLUSTER);
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/programmability/LiveRedisClusterTransactionTest.java:20:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.ConfiguredRedisPermitVerifier;
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/programmability/LiveRedisClusterTransactionTest.java:21:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.ConfiguredRedisPolicyAuthority;
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/programmability/LiveRedisClusterTransactionTest.java:110: ConfiguredRedisPolicyAuthority authority =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/programmability/LiveRedisClusterTransactionTest.java:111: new ConfiguredRedisPolicyAuthority(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/programmability/LiveRedisClusterTransactionTest.java:116: ConfiguredRedisPermitVerifier verifier =
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/programmability/LiveRedisClusterTransactionTest.java:117: new ConfiguredRedisPermitVerifier(authority, endpoint.mode());
exit=0
$ git grep -n 'requireWriteDurability\|\.confirm(' -- 'adapter/outbound/cache-redis/src'
adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbe.java:133: public void requireWriteDurability(
adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettings.java:888: * signal exists for it; see {@link RedisCapabilityProbe#requireWriteDurability}.
adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbe.java:61: probe.requireWriteDurability(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbeTest.java:113: assertThatThrownBy(() -> probe.requireWriteDurability(mode, 0, 10, false))
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbeTest.java:122: probe.requireWriteDurability(RedisDeploymentMode.SENTINEL, 1, 10, false);
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbeTest.java:123: probe.requireWriteDurability(RedisDeploymentMode.CLUSTER, 2, 5, false);
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbeTest.java:133: assertThatThrownBy(() -> probe.requireWriteDurability(mode, 2, 0, false))
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbeTest.java:142: probe.requireWriteDurability(RedisDeploymentMode.SENTINEL, 0, 0, true);
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisCapabilityProbeTest.java:148: probe.requireWriteDurability(RedisDeploymentMode.STANDALONE, 0, 0, false);
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java:51: probe.confirm(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java:69: probe.confirm(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java:83: probe.confirm(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java:97: probe.confirm(
adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisStartupProbeTest.java:137: probe.confirm(
exit=0
=== 8.1e app-bootstrap가 RedisCorrectnessRoles를 실제로 읽는가 ===
$ git grep -rn 'RedisCorrectnessRoles\|redisRequired\|redisOptional' -- app-bootstrap | head -20
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessor.java:3:import dev.caskeleton.adapter.outbound.cache.redis.sdk.config.RedisCorrectnessRoles;
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessor.java:20: * contributor 'redisRequired' in group 'readiness' does not exist}. So a static {@code
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessor.java:21: * readiness.include} listing {@code redisRequired} is not "tolerated when Redis is off" — it is a
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessor.java:30: * Hence this post-processor. It reads {@link RedisCorrectnessRoles} — the identical predicate
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessor.java:45: if (!redisEnabled(environment) || !RedisCorrectnessRoles.anySelected(environment)) {
app-bootstrap/src/main/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessor.java:54: if (!members.add(RedisCorrectnessRoles.REQUIRED_HEALTH_CONTRIBUTOR)) {
app-bootstrap/src/main/resources/application.yml:272: # unconditional contributors, and the one conditional member — `redisRequired` — is appended
app-bootstrap/src/main/resources/application.yml:292: # `redisRequired` is NOT listed here, and must not be: group membership does not tolerate a
app-bootstrap/src/main/resources/application.yml:295: # startup with "Included health contributor 'redisRequired' in group 'readiness' does not
app-bootstrap/src/main/resources/application.yml:298: # `redisOptional` is never appended: a cache outage is reported as degraded detail and never
app-bootstrap/src/test/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessorTest.java:107: assertThat(readiness.isMember("redisRequired"))
app-bootstrap/src/test/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessorTest.java:110: assertThat(context.getBeansOfType(HealthIndicator.class)).doesNotContainKey("redisRequired");
app-bootstrap/src/test/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessorTest.java:123: .containsKey("redisOptional")
app-bootstrap/src/test/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessorTest.java:124: .doesNotContainKey("redisRequired");
app-bootstrap/src/test/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessorTest.java:125: assertThat(readiness.isMember("redisRequired")).isFalse();
app-bootstrap/src/test/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessorTest.java:126: assertThat(readiness.isMember("redisOptional"))
app-bootstrap/src/test/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessorTest.java:139: assertThat(context.getBeansOfType(HealthIndicator.class)).containsKey("redisRequired");
app-bootstrap/src/test/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessorTest.java:140: assertThat(readiness.isMember("redisRequired"))
app-bootstrap/src/test/java/dev/caskeleton/bootstrap/runtime/RedisReadinessGroupPostProcessorTest.java:166: .isMember("redisRequired"))
app-bootstrap/src/test/java/dev/caskeleton/bootstrap/runtime/RuntimeHealthLifecycleContractTest.java:98: // The shipped file names only contributors that always exist. Both `redisRequired` and `db` are
exit=0
=== 8.2b RedisSdkSettings.validate 규칙 목록 ===
$ grep -n 'private void require\|violations.add\|warnings.add\|throw new IllegalStateException' adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/config/RedisSdkSettings.java | head -60
61: throw new IllegalStateException("Cluster supports database 0 only");
64: throw new IllegalStateException("database index must not be negative");
67: throw new IllegalStateException("at least one Redis node must be configured");
77: throw new IllegalStateException("blocking commands must not be unbounded");
80: throw new IllegalStateException("dedicated connection lanes need a positive ceiling");
84: throw new IllegalStateException(
95: throw new IllegalStateException(
101: warnings.add(
110: throw new IllegalStateException("the raw gateway requires an allowlist resource");
114: throw new IllegalStateException(
120: throw new IllegalStateException(
125: throw new IllegalStateException(
138: throw new IllegalStateException(name + " timeout must be positive");
141: throw new IllegalStateException(
145: warnings.add(
255: throw new IllegalStateException(
268: throw new IllegalStateException("every Redis SDK limit must be positive");
409: throw new IllegalStateException(
418: warnings.add(
426: warnings.add(
570: throw new IllegalStateException("the client name must not be blank");
578: throw new IllegalStateException("the shutdown quiet period must not be negative");
581: throw new IllegalStateException(
589: throw new IllegalStateException(name + " timeout must be positive");
658: throw new IllegalStateException("cluster maximum redirects must be positive");
663: throw new IllegalStateException("the cluster topology refresh period must be positive");
694: throw new IllegalStateException("every Redis capacity ceiling must be positive");
748: throw new IllegalStateException("the pub/sub buffer capacity must be positive");
751: throw new IllegalStateException(
exit=0
$ grep -n 'public List