Sub-scope 05 (inbound-web) idempotency + operation + operationasync + evidence revision=a24ece9cf797f7ea647e33bf846b115208ed1ba5 generatedAt=2026-08-30T07:26:46+00:00 === OWNED FILES === 09b8372242c82d595ee2f9c3666ca578b676fe27 main/java/dev/caskeleton/adapter/inbound/web/evidence/WebApplicationEvidence.java 44 2b2d95ea7c6b1c08efa9daa27ea35dd2ce7f8bfe main/java/dev/caskeleton/adapter/inbound/web/evidence/WebEvidenceAxis.java 15 9d50db0ade99d79433193c095679d079fdb34770 main/java/dev/caskeleton/adapter/inbound/web/evidence/WebExecutionEvidence.java 57 3a6dc3e2292e7ea77f973bd77a68c3461fbe6a48 main/java/dev/caskeleton/adapter/inbound/web/evidence/WebExecutionEvidenceTracker.java 125 ea8eed7e43c59f73c57c29219e59977680a52dcc main/java/dev/caskeleton/adapter/inbound/web/evidence/WebRequestPhase.java 44 269ab58d05e149e802c6d1f1ba8965960b8804f7 main/java/dev/caskeleton/adapter/inbound/web/evidence/WebResponseEvidence.java 46 401ffe547bfb75201bdcb493ec2ad1b31bbde4fe main/java/dev/caskeleton/adapter/inbound/web/idempotency/DeterministicCommandEncoder.java 74 e97ca5b43539cc0cbab27197a30f15cdfb41b6be main/java/dev/caskeleton/adapter/inbound/web/idempotency/FingerprintHeaderPolicy.java 102 6bc27398702703e6296473ce7d5fdbf7a382bc25 main/java/dev/caskeleton/adapter/inbound/web/idempotency/IdempotencyAdmission.java 85 02e93a8b2b9bf830369021194517d05c8f90383e main/java/dev/caskeleton/adapter/inbound/web/idempotency/IdempotencyKey.java 33 0dc1a346d1d8d51249f39a1069ecea0d1f669864 main/java/dev/caskeleton/adapter/inbound/web/idempotency/IdempotencyKeySupport.java 66 3daf9dbddd62b03584f1e3d675eae8253b6a3b03 main/java/dev/caskeleton/adapter/inbound/web/idempotency/IdempotencyResponsePlan.java 97 e6563e02b7814ec4374cb66a67d2ea756672fa5c main/java/dev/caskeleton/adapter/inbound/web/idempotency/JsonIdempotentResponseCodec.java 44 bcdecedf0ae006aceb630d4377fc020ac3bf7598 main/java/dev/caskeleton/adapter/inbound/web/idempotency/SemanticRequestFingerprintFactory.java 94 d4c5c53c1ef4609e56b1c2057ae673920512c83c main/java/dev/caskeleton/adapter/inbound/web/idempotency/WebIdempotencyGate.java 180 7a0ba511685fb7086e06f62eb8aa79ca139ccd0a main/java/dev/caskeleton/adapter/inbound/web/mvc/idempotency/IdempotentResponseWriter.java 84 aceb3928ef9d8321e1c130a8ee0a4536bbe7d43e main/java/dev/caskeleton/adapter/inbound/web/mvc/idempotency/WebMvcIdempotentInvoker.java 108 0f5c4dfde6c99cf4e5f762f1cd962a07465e26fd main/java/dev/caskeleton/adapter/inbound/web/mvc/operation/OperationHttpController.java 105 f333b4eae4f8169f71a6b1e46088f199c416ceef main/java/dev/caskeleton/adapter/inbound/web/operation/AdmissionProfileName.java 35 6a9b1ebfadd3b7fad907d6b4d3849af2229e83cb main/java/dev/caskeleton/adapter/inbound/web/operation/AuthorizationProfileName.java 35 d9715d2f988d62a1630000dad36f7f9e52a989c1 main/java/dev/caskeleton/adapter/inbound/web/operation/CachePolicyName.java 35 1d36292c292382371d5ebed1b32b0b1fe619592c main/java/dev/caskeleton/adapter/inbound/web/operation/HttpMethodSemantic.java 54 3a0f6f5784d856454b7b5ff8778f07db12fcaf8f main/java/dev/caskeleton/adapter/inbound/web/operation/IdempotencyPolicy.java 20 dc03e5d24fa694498053cc7ce988182507d761cc main/java/dev/caskeleton/adapter/inbound/web/operation/InMemoryWebOperationCatalog.java 61 826c260984a2d3de253cb01aaf3ed82cd64528c2 main/java/dev/caskeleton/adapter/inbound/web/operation/MutationKind.java 38 916ad6adb9ae107737789fb43efd472ba56852da main/java/dev/caskeleton/adapter/inbound/web/operation/PreconditionPolicy.java 21 1c17d83ecbe49279203ac45eb1e16489c879bf47 main/java/dev/caskeleton/adapter/inbound/web/operation/ResponseProfileName.java 35 53572651a5b29d37b9a6994ab206496b3a2f4ce9 main/java/dev/caskeleton/adapter/inbound/web/operation/WebOperationCatalog.java 28 225984be514179238b0740670f724ee6ce662a9a main/java/dev/caskeleton/adapter/inbound/web/operation/WebOperationProfile.java 119 1bc8022b2b9b08660c06c66b29c7c3f28c2791ba main/java/dev/caskeleton/adapter/inbound/web/operationasync/OperationAccessPolicy.java 42 ee641d0b4f594fb8cc82b4f7886d834153c76b37 main/java/dev/caskeleton/adapter/inbound/web/operationasync/OperationId.java 29 1c2a0d2dc8569e4af92ccd7a1fe9de8368ab54d8 main/java/dev/caskeleton/adapter/inbound/web/operationasync/OperationProgress.java 50 ba9351e26f8dbf3f3f8d1d8cd81fcc49bf48aece main/java/dev/caskeleton/adapter/inbound/web/operationasync/OperationQueryService.java 74 37a69e38dd86724c908e5e347bf29856b453f45c main/java/dev/caskeleton/adapter/inbound/web/operationasync/OperationResource.java 159 441aaca5389c99c568f16eefe7eeda13066695d8 main/java/dev/caskeleton/adapter/inbound/web/operationasync/OperationResourceFactory.java 112 c3c340fe86f9f816711d42988ddb8b8cba101484 main/java/dev/caskeleton/adapter/inbound/web/operationasync/OperationResponse.java 56 00453ac2722e568d28d4e33d50db2fdb99dfc1e4 main/java/dev/caskeleton/adapter/inbound/web/operationasync/OperationResponseMapper.java 43 fd905407b7c0ca864c80eccc3f7d6e988e081b18 main/java/dev/caskeleton/adapter/inbound/web/operationasync/OperationStatus.java 40 8129f0895798453076bd9af97440617c9f412e20 main/java/dev/caskeleton/adapter/inbound/web/webflux/idempotency/WebFluxIdempotentInvoker.java 168 23ad8ee4b0a4113872e15374b44ad2efdda0ef42 main/java/dev/caskeleton/adapter/inbound/web/webflux/operation/ReactiveOperationHttpController.java 106 9dc9f2412a5d6287533e0b85cb49073131a92c57 test/java/dev/caskeleton/adapter/inbound/web/evidence/WebExecutionEvidenceTrackerTest.java 156 b531bd2a9f21c6c92c66f3e903a462cbdfaa8bf3 test/java/dev/caskeleton/adapter/inbound/web/idempotency/IdempotencyKeySupportTest.java 80 6b41124404aa453a69157860a914a4a2bdb89398 test/java/dev/caskeleton/adapter/inbound/web/idempotency/InMemoryIdempotencyStore.java 70 03ddbb79c4c27e9923a5fa30916443b42e4a73a7 test/java/dev/caskeleton/adapter/inbound/web/idempotency/SemanticRequestFingerprintFactoryTest.java 140 bd2825015460b787bdba7bdc463d38c1e4f33778 test/java/dev/caskeleton/adapter/inbound/web/idempotency/WebIdempotencyGateTest.java 343 2636c7fb45114d566c58c720fe82a3879b9aa433 test/java/dev/caskeleton/adapter/inbound/web/mvc/idempotency/WebMvcIdempotentInvokerTest.java 288 93b8a0dcf5ac710ffaa337c7dafe7efdf0c0c06a test/java/dev/caskeleton/adapter/inbound/web/operation/WebOperationCatalogTest.java 141 787e4a5fbd4b4bc4863e92a590e035ca9668300a test/java/dev/caskeleton/adapter/inbound/web/operationasync/OperationAccessPolicyTest.java 122 5ea653c8698c2aab6095b1ac45b41a3a3abdcc04 test/java/dev/caskeleton/adapter/inbound/web/operationasync/OperationResourceTest.java 230 aa70c62a7d7441f545e241e4c48954658731af97 test/java/dev/caskeleton/adapter/inbound/web/webflux/idempotency/WebFluxIdempotentInvokerTest.java 268 file_count=50 === 8.1 도달성: 멱등성 실행 계층과 durable-operation 표면 === WebIdempotencyGate 5 test 2 testkit WebMvcIdempotentInvoker 1 test 1 testkit WebFluxIdempotentInvoker 1 test 1 testkit IdempotentResponseWriter 1 test 1 testkit SemanticRequestFingerprintFactory 6 test 2 testkit OperationQueryService 1 testkit OperationResourceFactory 1 testkit WebExecutionEvidenceTracker 1 main $ grep -rn 'inbound.web.idempotency\|WebIdempotencyGate\|IdempotencyKeySupport' --include=*.java app-bootstrap/src/main | wc -l 0 exit=0 $ grep -rn 'IdempotencyKeySupport' --include=*.java adapter/inbound/web/src/main sample-portfolio/src/main | grep -v IdempotencyKeySupport.java | wc -l 0 exit=0 === 8.2 durable-operation 컨트롤러의 게이트와 의존 === $ grep -n 'ConditionalOnProperty' -A 4 adapter/inbound/web/src/main/java/dev/caskeleton/adapter/inbound/web/mvc/operation/OperationHttpController.java | tail -5 35:@ConditionalOnProperty( 36- prefix = "app.web-platform.durable-operations", 37- name = "enabled", 38- havingValue = "true") 39-@RequestMapping(OperationHttpController.BASE_PATH) exit=0 $ grep -rn 'app.web-platform.durable-operations' --include=*.yml --include=*.yaml --include=*.java . | sed 's|adapter/inbound/web/src/||' ./main/java/dev/caskeleton/adapter/inbound/web/mvc/operation/OperationHttpController.java:36: prefix = "app.web-platform.durable-operations", ./main/java/dev/caskeleton/adapter/inbound/web/webflux/operation/ReactiveOperationHttpController.java:37: prefix = "app.web-platform.durable-operations", exit=0 $ grep -rn 'OperationQueryService' --include=*.java adapter/inbound/web/src/main app-bootstrap/src/main | grep -v 'OperationQueryService.java' | sed 's|.*/web/||' mvc/operation/OperationHttpController.java:6:import dev.caskeleton.adapter.inbound.web.operationasync.OperationQueryService; mvc/operation/OperationHttpController.java:45: private final OperationQueryService operations; mvc/operation/OperationHttpController.java:52: public OperationHttpController(OperationQueryService operations) { webflux/operation/ReactiveOperationHttpController.java:6:import dev.caskeleton.adapter.inbound.web.operationasync.OperationQueryService; webflux/operation/ReactiveOperationHttpController.java:28: * {@link OperationQueryService}, which both call. What differs is only what has to: the store is webflux/operation/ReactiveOperationHttpController.java:46: private final OperationQueryService operations; webflux/operation/ReactiveOperationHttpController.java:56: OperationQueryService operations, Scheduler blockingScheduler) { exit=0 === 8.3 WebOperationCatalog 를 읽는 쪽 === $ grep -rn 'WebOperationCatalog' --include=*.java adapter/inbound/web/src/main app-bootstrap/src/main | grep -v 'operation/WebOperationCatalog.java\|InMemoryWebOperationCatalog.java' | sed 's|.*/web/||' mvc/autoconfigure/WebMvcPlatformAutoConfiguration.java:17:import dev.caskeleton.adapter.inbound.web.operation.InMemoryWebOperationCatalog; mvc/autoconfigure/WebMvcPlatformAutoConfiguration.java:18:import dev.caskeleton.adapter.inbound.web.operation.WebOperationCatalog; mvc/autoconfigure/WebMvcPlatformAutoConfiguration.java:58: @ConditionalOnMissingBean(WebOperationCatalog.class) mvc/autoconfigure/WebMvcPlatformAutoConfiguration.java:59: public InMemoryWebOperationCatalog webOperationCatalog() { mvc/autoconfigure/WebMvcPlatformAutoConfiguration.java:60: return new InMemoryWebOperationCatalog(); webflux/autoconfigure/WebFluxPlatformAutoConfiguration.java:13:import dev.caskeleton.adapter.inbound.web.operation.InMemoryWebOperationCatalog; webflux/autoconfigure/WebFluxPlatformAutoConfiguration.java:14:import dev.caskeleton.adapter.inbound.web.operation.WebOperationCatalog; webflux/autoconfigure/WebFluxPlatformAutoConfiguration.java:76: @ConditionalOnMissingBean(WebOperationCatalog.class) webflux/autoconfigure/WebFluxPlatformAutoConfiguration.java:77: public InMemoryWebOperationCatalog webOperationCatalog() { webflux/autoconfigure/WebFluxPlatformAutoConfiguration.java:78: return new InMemoryWebOperationCatalog(); admin/route/WebRouteInventory.java:4:import dev.caskeleton.adapter.inbound.web.operation.WebOperationCatalog; admin/route/WebRouteInventory.java:50: public void requireRegisteredOperations(WebOperationCatalog catalog) { advanced/functional/FunctionalRoutePolicyValidator.java:3:import dev.caskeleton.adapter.inbound.web.operation.WebOperationCatalog; advanced/functional/FunctionalRoutePolicyValidator.java:22: private final WebOperationCatalog catalog; advanced/functional/FunctionalRoutePolicyValidator.java:24: public FunctionalRoutePolicyValidator(WebOperationCatalog catalog) { advanced/functional/FunctionalRouteRegistry.java:3:import dev.caskeleton.adapter.inbound.web.operation.WebOperationCatalog; advanced/functional/FunctionalRouteRegistry.java:25: public FunctionalRouteRegistry(WebOperationCatalog catalog) { exit=0 === 8.4 fingerprint 정규화 형식 === $ grep -n 'SEPARATOR\|canonical.append' adapter/inbound/web/src/main/java/dev/caskeleton/adapter/inbound/web/idempotency/SemanticRequestFingerprintFactory.java 36: private static final char SEPARATOR = '\u001f'; 68: canonical.append(operation.value()); 71: (name, value) -> canonical.append(SEPARATOR).append(name).append('=').append(value)); 72: canonical.append(SEPARATOR).append(encoder.canonicalize(command)); 76: (name, value) -> canonical.append(SEPARATOR).append(name).append(':').append(value)); exit=0 $ grep -rn 'ByteBuffer.allocate(Integer.BYTES)\|putInt(encoded.length)' --include=*.java adapter | wc -l 17 exit=0