Sub-scope 03 (cache-redis) sdk/api/key + error + command + reactive — manifest and probes revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5 generatedAt=2026-08-30T04:41:02+00:00 === OWNED FILES === 7d962093375f0c36434d719a09907a754381fba3 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/AdvancedOperationPermit.java 19 e4a4f7d278375104757f5ecd0a3c346d5ca7da31 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/CommandAccess.java 17 131e7c9bbdd7a2e23f0d8d0957c72c37cb6c585d main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/CommandId.java 85 6112df8fa18da163230367f89313984aba55c367 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/CommandSupport.java 17 360a583fbefc2bdd84587bb477ece62a5e20a2a5 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/KeySpec.java 76 fe9a3abb85761461514966f8d1405ee531625cd8 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/MultiKeyPermit.java 16 05028e3b1776e895906398640fb1dcbabedef274 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/OperationBudget.java 54 c37cf3b690f18a08ada8832eab4cfe3994dd8148 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/PersistentKeyPermit.java 16 4bf3808adfef86de7ef1052a3141a7c8fedeec4c main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/RedisCommandDescriptor.java 60 afb4b1bf976b42e9688efc76cea1aacded73d96c main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/RedisPermitVerifier.java 34 169daebddd2191ef5d74820b224aad5561ec9133 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/RedisPolicyAuthority.java 34 81a060369f496b1d00cc107b8d299b0acef1052a main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/RedisRiskLevel.java 31 447e777029e7682f6db4560a3fad669d4ee7861c main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/TimeoutProfile.java 42 2cbe99146bf79f371b9e3a171645cf5efa168c02 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisAccessDeniedException.java 28 50d3fdc25bd971caa27a8491939a62b13210d1fa main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisAmbiguousExecutionException.java 31 582d3dc835dee3ac3e3e1f82a79b1086dd335ab1 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisBusyException.java 28 d3e2640731f096877327f5b001786ee25eb911a4 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisCapabilityUnavailableException.java 29 4c40194c7e1f58b3c86c2d6b600e7cdb8ddc9121 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisCommandRejectedException.java 29 c4a8e084d5670092265d860b93a316004bccdf35 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisConnectionException.java 28 3fc7929765ff43d2f45c295e6dcc45b137595aea main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisCrossSlotException.java 28 0572a35da76bd519b6a330bf6e7d18ed627e775f main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisDataTypeMismatchException.java 29 a402d3b6c7370647521d0168e1f4e8eaaa3f7615 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisFailureMetadata.java 106 a96ed0bf7af82ec61fcb1b04d0728c54def23140 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisNoScriptException.java 28 d558d87666acd779b42692013bb760890f65b62b main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisOperationException.java 58 11985da1f6c97dbeb55d7337c5677255ec990c50 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisRedirectionException.java 28 4f6cc4740449cc386983c7d561bbd50570783fb5 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisSerializationException.java 32 db98a87e30b031319274ca50008877b6d7531994 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisTimeoutException.java 28 3b16f5498a0845e2b229434dd97b7f60010f9162 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/BitmapKey.java 17 eb8c5391da357f39ef13dfda4f62a1551bd551d2 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/GeoKey.java 19 e73bac153261577fc9be192a7d88df4e8b932429 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/HashKey.java 24 46d7ff5dfd5dc47c1e16264fe84bd07c79ba0751 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/HyperLogLogKey.java 20 21f1498ac07bbdfabc99b57dbb809f46d1a9c226 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/ListKey.java 20 c572cb9c1d6c4ddddfcb8d47fd0506c098094847 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/QualifiedRedisKey.java 49 5dfaa3350559cff62d0ea587d964ed4d38dc9ee5 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/RedisKeyName.java 15 f9ec9cd3ac14adcd50f1816fef01fa689ded8370 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/RedisKeyRenderer.java 69 55a7b9d74b3c8e48e872de189f318ab475edad1a main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/RedisKeyRules.java 101 56c73270d657b105ffd1454671efad1cddfded65 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/RedisNamespace.java 29 6203eeb20f8e52ef8fc25cd569f121fa67e4c113 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/RedisSlotTag.java 17 3b6ab0a06a2b425f0b56c189722f70291fd58e60 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/RedisTypedKey.java 26 73238fa9db52df2498392e599c5e92e2fd966e69 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/SetKey.java 19 fd2d1444bca91ed05c71eb1cbb60a1fcf035a440 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/SortedSetKey.java 20 9de8ed5736db8ea61abecbfc3a673afa4c889518 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/StreamKey.java 20 ce887cd0141b876bdf057fc3e791271886e34aa1 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/TypedRedisKeys.java 217 4a0371eb46afe4aa9bc3bf866bf456f86c00a1e1 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/ValueKey.java 20 544c98b1e8070aceec7cb0ac72145a9738c57454 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisBatchOperations.java 19 fb776ae0d021527e7d943c2caf2827ef7d254cb4 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisBitFieldOperations.java 28 a58ae7b617c8a459906224680ff6571a08aeb76f main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisBitmapOperations.java 69 6168d8c02497f01f218aef7b96d24c3173f3a1bb main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisBlockingListOperations.java 48 e11b517f2a1921b5b40f5d79eee79b9eb3d41922 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisBlockingStreamOperations.java 46 2f6a10d87deea0ac91617bb01c37f0229fc0b5e5 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisGeoOperations.java 82 598e00d8481b8fe1aef4ce9253f6e4a7a167258c main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisHashFieldExpirationOperations.java 51 269ce5a7289e3e771e47c20e317929d0dffe6d17 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisHashOperations.java 150 fe7a26f6e8c33e39b8bfde63fe4eed0ef1b689b4 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisHyperLogLogOperations.java 42 682733bb7aea5fa65521d6ecda60256bb1e9428f main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisKeyOperations.java 133 f895b644161fbfbb40c29e107ab87fdbb1a51586 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisListOperations.java 160 8f8c69eb989cfd1d1537e4729b939aa6dabeef7c main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisPubSubOperations.java 44 650a75218a60ae8a655551f86070b728601cea8b main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisSetOperations.java 168 1b61d246aa7b5cb154566e7765a0617d373b1052 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisShardedPubSubOperations.java 29 26655ff49e817146815e436d1facaf97099d819a main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisSortedSetOperations.java 196 5443d0091ca147737ba0932d5ebbb8f25bc1efd9 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisStreamOperations.java 202 621356218e9051ba5b09709f6cf57c40889369e5 main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisValueOperations.java 163 d5b25f5ff10a32318609756fb03006d76faa6982 test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/OperationBudgetTest.java 36 8576733068fdf68d13b00d8b54d0952bbbb65225 test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/RedisKeyRendererTest.java 64 5439821ee078d9eee8a0a327e529ae1ce5e1f517 test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/RedisKeyRulesTest.java 69 main: 61 test: 3 === 8.1 도달 불가 검증 분기: requireIdentifier의 다섯 검사 === $ sed -n '22,30p;60,80p' adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/RedisKeyRules.java private static final Pattern IDENTIFIER = Pattern.compile("^[A-Za-z0-9][A-Za-z0-9._~-]{0,127}$"); private static final Pattern JSON_WEB_TOKEN = Pattern.compile("^[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}$"); private static final Pattern INTERNATIONAL_PHONE = Pattern.compile("^\\+\\d[\\d.~-]{7,}$"); private RedisKeyRules() { if (value == null || !IDENTIFIER.matcher(value).matches()) { throw new IllegalArgumentException( "identifier must be 1..128 characters of [A-Za-z0-9._~-] and must not contain a" + " key separator"); } String lowerCase = value.toLowerCase(Locale.ROOT); if (value.indexOf('@') >= 0) { throw new IllegalArgumentException("identifier must not contain a mail address"); } if (JSON_WEB_TOKEN.matcher(value).matches()) { throw new IllegalArgumentException("identifier must not contain a JSON web token"); } if (INTERNATIONAL_PHONE.matcher(value).matches()) { throw new IllegalArgumentException("identifier must not contain a phone number"); } if (lowerCase.startsWith("bearer") || lowerCase.startsWith("eyj")) { throw new IllegalArgumentException("identifier must not contain authentication material"); } return value; } exit=0 --- IDENTIFIER 문자 클래스가 '@'와 '+'를 이미 배제하는가 --- $ grep -n 'IDENTIFIER =' adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/RedisKeyRules.java 23: private static final Pattern IDENTIFIER = Pattern.compile("^[A-Za-z0-9][A-Za-z0-9._~-]{0,127}$"); exit=0 $ grep -n 'rejectsEmailInIdentifier' -A 5 adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/RedisKeyRulesTest.java 12: void rejectsEmailInIdentifier() { 13- assertThatThrownBy(() -> new RedisKeyName("user", "person@example.com")) 14- .isInstanceOf(IllegalArgumentException.class); 15- } 16- 17- @Test exit=0 $ grep -n 'rejectsInternationalPhoneNumbersInIdentifier' -A 8 adapter/outbound/cache-redis/src/test/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/key/RedisKeyRulesTest.java 31: void rejectsInternationalPhoneNumbersInIdentifier() { 32- assertThatThrownBy(() -> new RedisKeyName("contact", "+821012345678")) 33- .isInstanceOf(IllegalArgumentException.class); 34- } 35- 36- @Test 37- void rejectsSeparatorInjectionInEveryKeyPart() { 38- assertThatThrownBy(() -> new RedisKeyName("user", "1:2")) 39- .isInstanceOf(IllegalArgumentException.class); exit=0 === 8.1b 선언되었으나 읽히지 않는 술어 === $ git grep -n 'requiresPermit()' -- 'adapter/outbound/cache-redis/src' adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/RedisRiskLevel.java:19: public boolean requiresPermit() { exit=0 $ git grep -n 'deniedToApplications()' -- 'adapter/outbound/cache-redis/src' adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/RedisRiskLevel.java:28: public boolean deniedToApplications() { adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/command/CommandPolicyGuard.java:126: if (policy.riskLevel().deniedToApplications() adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/raw/RawCommandApprovals.java:116: if (policy.riskLevel().deniedToApplications()) { exit=0 === 8.2 sync/reactive 대칭: getRange 포함 실제 대조 === $ grep -c ';' adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/operations/RedisValueOperations.java adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisValueOperations.java adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/operations/RedisValueOperations.java:20 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisValueOperations.java:25 exit=0 $ diff <(grep -oE '[a-z][A-Za-z]*\(' adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/operations/RedisValueOperations.java | sort -u) <(grep -oE '[a-z][A-Za-z]*\(' adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/reactive/ReactiveRedisValueOperations.java | sort -u) exit=0 === 8.2b RedisCommandDescriptor 교차 필드 불변식 === $ grep -n 'throw new IllegalArgumentException' -B 4 adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/command/RedisCommandDescriptor.java 30- Objects.requireNonNull(access, "access must be non-null"); 31- Objects.requireNonNull(keySpec, "key specification must be non-null"); 32- Objects.requireNonNull(timeoutProfile, "timeout profile must be non-null"); 33- if (support == CommandSupport.BLOCKED && access != CommandAccess.NONE) { 34: throw new IllegalArgumentException("a blocked command must not carry an ACL account"); 35- } 36- if (riskLevel == RedisRiskLevel.R4 && support != CommandSupport.BLOCKED) { 37: throw new IllegalArgumentException("an R4 command must be blocked"); 38- } 39- if (riskLevel == RedisRiskLevel.R3 40- && support != CommandSupport.ADMIN_ONLY 41- && support != CommandSupport.BLOCKED) { 42: throw new IllegalArgumentException("an R3 command must be admin-only or blocked"); 43- } 44- if (!readOnly && retrySafe && mayBeAmbiguous) { 45: throw new IllegalArgumentException( exit=0 === 8.3 실패 메타데이터: 모호 실행과 재시도의 배타 === $ grep -n 'ambiguousExecution\|retryable\|storedDataCorruption\|notSent' adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisFailureMetadata.java | head -20 21: boolean retryable, 22: boolean ambiguousExecution, 41: if (retryable && ambiguousExecution) { 42: throw new IllegalArgumentException("an ambiguous execution must never be marked retryable"); 61: *

Deliberately not {@link #notSent}: that factory derives {@code retryable} from {@code 71: * @return metadata marked not retryable and not ambiguous 73: public static RedisFailureMetadata storedDataCorruption( 90: public static RedisFailureMetadata notSent( exit=0 $ git grep -n 'storedDataCorruption(' -- 'adapter/outbound/cache-redis/src/main' | head adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisFailureMetadata.java:73: public static RedisFailureMetadata storedDataCorruption( adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/codec/JsonEnvelopeFraming.java:202: RedisFailureMetadata.storedDataCorruption( adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/lettuce/codec/VersionedJsonCodec.java:103: RedisFailureMetadata.storedDataCorruption( exit=0 === 8.4 예외 계층: transient metadata === $ grep -n 'transient\|serialVersionUID' adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error/RedisOperationException.java 14: private static final long serialVersionUID = 1L; 16: private final transient RedisFailureMetadata metadata; exit=0 $ git ls-files 'adapter/outbound/cache-redis/src/main/java/dev/caskeleton/adapter/outbound/cache/redis/sdk/api/error' | wc -l 14 exit=0