Files
document-haness/docs/clean-architecture-backend-template/source-index.md
T
DongHyeonkaandClaude Opus 5 b2963105a8 docs(keycloak-session-store): import the session-storage lab as a new project
The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.

Follows the import procedure in README.md.

  source/     the originating repository verbatim — 78 documents, 28 SVGs,
              8 manifests, plus .source-revision recording the commit
  final/      the SSOT
    document.md   729 lines written from the 29 experiment documents, not
                  concatenated: what was predicted, what was measured, and
                  where the measurement itself was wrong
    evidence/raw    125 outputs, flattened to <experiment>__<file> because
                    the originals collided (01-baseline.txt appeared three
                    times) and the audit only globs the top level
    evidence/meta   one per raw file; command and exitCode are null and the
                    README says why rather than inventing them
    evidence/browser  22 captures
    assets/       three diagrams through techviz
    .techviz/     their VizSpecs

A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.

Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.

verify-pipeline.py passes. audit-records.py reports no issues.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 22:51:59 +09:00

272 lines
139 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Source Index
상세 문서의 주장과 근거를 다시 찾을 수 있게 code/config/test/git/runtime source를 색인한다.
| id | kind | path / command / URL | revision or time | what it proves | limitations |
|---|---|---|---|---|---|
| SRC-001 | git | `evidence/raw/001-git-snapshot.txt` | `a24ece9cf797f7ea647e33bf846b115208ed1ba5` | 분석 snapshot과 clean branch 상태 | 이후 source 변경에는 적용 안 됨 |
| SRC-002 | registry/inventory | `src/config/architecture/modules.json`, `evidence/raw/002-module-inventory.txt` | same revision | 44 registered leaves, dependency/runtime memberships, initial file/LOC sizing | initial sizing은 각 bounded scope final denominator와 다를 수 있음 |
| SRC-003 | module policy | `src/domain-core/CLAUDE.md` | same revision | domain-core responsibility/allowed/forbidden/test contract | policy 문서; 실제 enforcement는 별도 확인 필요 |
| SRC-004 | rationale | `src/domain-core/README.md` | same revision | ResourceId unsealed, marker/guardrail rationale | 문서 claim은 code/test와 교차검증해야 함 |
| SRC-005 | code | `src/domain-core/src/main/java/dev/caskeleton/domain/identifier/ResourceId.java` | same revision | self-typed ID interface와 `value()` surface | UUIDv7 validation 구현 없음 |
| SRC-006 | code | `src/domain-core/src/main/java/dev/caskeleton/domain/identifier/IdFactory.java` | same revision | identifier generation port | concrete uniqueness/generation semantics는 adapter 책임 |
| SRC-007 | code | `src/domain-core/src/main/java/dev/caskeleton/domain/stereotype/*.java` | same revision | runtime-retained framework-neutral markers | marker 자체가 invariant를 구현하지 않음 |
| SRC-008 | build | `src/domain-core/build.gradle` | same revision | explicit module dependency block empty | convention plugin/tool dependencies는 root/build-logic에서 올 수 있음 |
| SRC-009 | build policy | `src/build-logic/.../ModuleRegistry.groovy`, `ca.architecture-registry.settings.gradle` | same revision | registry fail-closed validation과 project inclusion | runtime behavior 자체는 아님 |
| SRC-010 | build verification | `src/build.gradle:1401+ verifyCleanArchitectureDependencies` | same revision | actual project dependency edge와 allowlist 비교 | non-project external dependencies는 이 task 범위 밖 |
| SRC-011 | architecture test | `src/app-bootstrap/.../CleanArchitectureTest.java` domain rules | same revision | purity/value-object/aggregate/event/ResourceId enforcement | 전체 2,792라인 중 관련 rule만 bounded scope에서 해석 |
| SRC-012 | consumer code | `src/sample-portfolio/.../WorkLogId.java`, `WorkLogIdFactory.java`, `UuidWorkLogIdFactory.java` | same revision | ResourceId/IdFactory concrete reachability | sample implementation이지 모든 consumer를 대표하지 않음 |
| SRC-013 | consumer code | `src/sample-portfolio/.../WorkLog.java`, `WorkLogReserved.java` | same revision | AggregateRoot/DomainEvent production use | sample domain 전체 분석은 아님 |
| SRC-014 | test | `src/sample-portfolio/.../WorkLogIdPropertyTest.java` | same revision | canonical shape를 허용/비-shape를 거부 | UUID version/variant는 검증하지 않음 |
| SRC-015 | test | `src/sample-portfolio/.../UuidWorkLogIdFactoryTest.java` | same revision | factory canonical output/distinctness/monotonicity | global uniqueness proof 아님 |
| SRC-016 | runtime consumer | `src/adapter/inbound/websocket/.../LiveEventStompBroadcaster.java` | same revision | `DomainEvent` RUNTIME retention의 production reflection consumer 존재 | broadcaster 전체 behavior는 websocket scope 대상 |
| EVD-001 | command | `evidence/raw/003-domain-core-test.txt` | 2026-08-29 | `:domain-core:test` build task 실행 결과 | module 자체 Java test 0개 |
| EVD-002 | command | `evidence/raw/004-clean-architecture-test.txt` | 2026-08-29 | cross-module architecture test가 BUILD SUCCESSFUL / exit code 0 | 이 실행은 현재 snapshot의 전체 ArchUnit suite 결과이며 개별 rule의 미래 변경까지 보장하지 않음 |
| SRC-017 | module policy/rationale/build | `src/shared-contract/CLAUDE.md`, `README.md`, `build.gradle` | same revision | stdlib-only boundary, responsibilities, custom qualification lanes | policy/rationale claims are cross-checked against code/tests |
| SRC-018 | code/resource | `src/shared-contract/src/main/**` | same revision | shared error/response/rate-limit/metrics/tracing/concurrency/opstore/activation/health contracts and messaging schema | downstream adapter behavior belongs to their bounded scopes |
| SRC-019 | tests | `src/shared-contract/src/test/**`, `src/edgeRateLimitContractTest/**` | same revision | constructor/factory invariants, vocabulary, resource digest and provider-neutral rate-limit contract | does not prove external JSON Schema validator interoperability |
| SRC-020 | reachability | production references to `DomainContextPropagator` and `OperationalRecordStorePort` | same revision | actual app-bootstrap/JPA/sample/GraphQL consumers exist | representative reachability, not exhaustive consumer analysis |
| EVD-005 | command | `evidence/raw/005-shared-contract-test.txt` | 2026-08-29 | `:shared-contract:test` BUILD SUCCESSFUL / exit 0 | focused module test only |
| EVD-006 | command | `evidence/raw/006-shared-contract-edge-rate-limit-test.txt` | 2026-08-29 | strict `edgeRateLimitContractTest` BUILD SUCCESSFUL / exit 0 | provider-neutral contract lane only |
| SRC-021 | code/tests | `src/application-core/src/main/java/dev/caskeleton/application/{usecase,command,query,capability}/**`, matching `src/test/**` | same revision | framework-free use-case type split and runtime-readable capability declaration surface | mandatory/coherence enforcement still requires architecture-rule trace |
| SRC-022 | transaction code/tests | `src/application-core/src/main/java/dev/caskeleton/application/transaction/{TransactionMode,TransactionPort,PolicyTransactionPort,TransactionRequest}.java`, `TransactionPortTest.java`, `TransactionRequestTest.java` | same revision | transaction mode surface, root-write abstract contract, runnable delegation, request coherence validation | remaining transaction package and concrete adapter semantics not yet fully read |
| SRC-023 | security code/tests | `src/application-core/src/main/java/dev/caskeleton/application/security/**`, `AuthorizationContractTest.java`, `ObjectAccessPolicyTest.java` | same revision | framework-neutral permission/object-access contracts, invariants, transport-neutrality regression history | actual web interception/translation and production policy implementation belong to consumer traces |
| SRC-024 | transaction code/tests | `src/application-core/src/main/java/dev/caskeleton/application/transaction/**`, matching `src/test/**` | same revision | full application transaction vocabulary, policy request/result algebra, reconciliation and retry-safety contracts | framework execution semantics require adapter trace |
| SRC-025 | adapter code/test | `src/adapter/outbound/persistence-jpa/.../transaction/SpringTransactionPort.java`, `SpringTransactionPortTest.java` | same revision | REQUIRED/REQUIRES_NEW mapping, explicit READ_COMMITTED, root ambient rejection, commit-before-return and commit-failure behavior | focused fake transaction manager; broader policy executor belongs persistence-jpa scope |
| SRC-026 | architecture test | `src/app-bootstrap/.../CleanArchitectureTest.java` capability/repository/transaction/auth rules | same revision | mandatory UseCaseCapability, direct transaction/repository coherence, mutating permission declaration, Spring Security dependency ban | direct-call static analysis has documented helper/AOP blind spots |
| EVD-007 | command | `./gradlew :application-core:test` | 2026-08-29 | application-core tests BUILD SUCCESSFUL | module tests do not alone prove adapter/runtime semantics |
| EVD-008 | command | `./gradlew :app-bootstrap:test --tests dev.caskeleton.bootstrap.architecture.CleanArchitectureTest` | 2026-08-29 | architecture test task resolved BUILD SUCCESSFUL | Gradle reported task UP-TO-DATE; verifies current cached inputs/output state rather than fresh test execution |
| SRC-027 | application reliability code/tests | `src/application-core/src/main/java/dev/caskeleton/application/{idempotency,inbox,outbox,operation}/**`, matching `src/test/**` | same revision | owner-safe idempotency/inbox/outbox/durable-operation state, uncertainty and retry/reconciliation semantics | concrete persistence/provider implementation details belong to later scopes |
| SRC-028 | cache/coordination code/tests | `src/application-core/src/main/java/dev/caskeleton/application/{cache,lease,lock,outbound,observability}/**`, matching `src/test/**` | same revision | cache-aside race control, bounded single-flight/bulkhead, efficiency-only lease/lock contracts, low-cardinality outbound/observation semantics | actual Redis/JDBC provider failure behavior belongs to adapter scopes |
| SRC-029 | messaging/realtime code/tests | `src/application-core/src/main/java/dev/caskeleton/application/{messaging,realtime}/**`, matching messaging tests | same revision | provider/transport-neutral messaging catalog/event envelope and realtime durability/replay/presence contracts | full broker/websocket runtime behavior is cross-scope |
| SRC-030 | storage/publication code/tests | `src/application-core/src/main/java/dev/caskeleton/application/{storage,fileexport,filepublication}/**`, matching tests | same revision | legacy raw-storage compatibility path versus semantic publication contracts and CSV safety rules | legacy removal completion not established |
| SRC-031 | objectstorage code/tests | `src/application-core/src/main/java/dev/caskeleton/application/objectstorage/**`, matching tests | same revision | opaque identities, bounded content streaming, staged verification/publish, fencing, grants and privilege separation | concrete provider implementation is later outbound objectstorage scope |
| SRC-032 | fileserver code/tests | `src/application-core/src/main/java/dev/caskeleton/application/fileserver/**`, matching tests | same revision | upload/download lifecycle, writer fencing, cleanup/recovery, quota, HTTP/range/content-safety and physical/metadata ambiguity handling | concrete fileserver adapter/runtime workers are cross-scope |
| SRC-033 | notification code/tests | `src/application-core/src/main/java/dev/caskeleton/application/notification/**`, matching tests | same revision | typed public API, protected contacts, routing, dispatch uncertainty, callbacks, provider evidence, admin/operator contracts | concrete adapters/provider SDK semantics are later scopes |
| SRC-034 | reachability | `evidence/raw/013-application-core-reachability.txt`, `evidence/raw/013-application-core-reachability-command.sh` | 2026-08-29 | external production reference files for major application packages, distinguishing active/legacy/unwired paths | static references prove reachability, not that every referenced code path executes in every deployment |
| SRC-035 | build | `src/application-core/build.gradle`, root `src/build.gradle` messaging evidence/qualification configuration | same revision | shared-contract-only production dependency, strict messaging qualification required classes and fail-closed evidence properties | build policy does not itself prove runtime behavior |
| SRC-036 | defect trace | `AdminOperationStorePort.java`, `NotificationAdminApplicationService.java`, `JpaAdminOperationStore.java` | same revision | atomic admin claim contract and adapter implementation exist, while application service still uses find-before-effect/save and never calls claim | concurrency impact is statically demonstrated by control flow/history; dedicated reproducer remains backlog |
| EVD-009 | command | `evidence/raw/009-application-core-test.txt` | 2026-08-29 | fresh `:application-core:test --rerun-tasks` BUILD SUCCESSFUL | application-core test lane does not replace provider integration tests |
| EVD-010 | command | `evidence/raw/010-application-core-messaging-qualification.txt`, `010a-messaging-qualification-missing-attestation.txt`, `014-application-core-verification-metadata.txt` | 2026-08-29 | strict messaging application qualification: missing attestation fails closed; exact digest rerun passes 15 tests with 0 skipped | digests identify this analysis invocation, not a broader release attestation |
| EVD-011 | command | `evidence/raw/011-clean-architecture-test.txt` | 2026-08-29 | fresh CleanArchitectureTest rerun BUILD SUCCESSFUL, 98 actionable tasks executed | static architecture tests retain documented indirect-call/reflection/AOP blind spots |
| EVD-012 | command | `evidence/raw/012-verify-clean-architecture-dependencies.txt` | 2026-08-29 | `verifyCleanArchitectureDependencies` BUILD SUCCESSFUL | validates project dependency registry edges, not arbitrary runtime calls |
| SRC-037 | module code/test/build/docs | `src/adapter/outbound/support/{src/**,build.gradle,README.md,CLAUDE.md}` | same revision | complete leaf-owned surface: MDC correlation lookup, shared fail-open dependency logger, default Spring bean seam, focused test and local design claims | downstream adapter behavior and full app runtime are outside the leaf denominator and require separate consumer/composition evidence |
| SRC-038 | registry/composition/architecture | `src/config/architecture/modules.json`, `src/app-bootstrap/.../CaSkeletonApplication.java`, `CleanArchitectureTest.java`, `src/app-bootstrap/build.gradle` | same revision | support runtime membership, broad component-scan reachability, direct app-bootstrap dependency, and outbound-peer rule allowing shared dependency into support | source/ArchUnit wiring does not prove every deployment creates or exercises every consumer path |
| SRC-039 | consumer code/tests | `OutboundMessagePublisher.java`, `FailOpenNotificationProvider.java`, `OutboundMessagePublisherTest.java`, `NotificationAdapterTest.java`, `OptionalAdapterBeanGatingTest.java` | same revision | actual messaging/notification use of the shared logger, messaging diagnostic-failure isolation regression, current notification test coverage, and optional-adapter gating harness | only the support-relevant consumer paths were read; messaging/notification modules are not exhaustively analyzed in this scope |
| SRC-040 | logging/privacy contracts | `application-core/.../Notification.java`, notification provider/client SPIs, `app-bootstrap/.../LogMaskingPatterns.java`, relevant app-bootstrap README logging section, `docs/registries/mdc-keys.yaml` | same revision | Notification recipient/body PII contract, unrestricted exception surfaces, current secret-masking vocabulary, and correlation-id registry ownership | does not establish the exception text behavior of every external SDK or every production log backend |
| SRC-041 | git/document history | `git log -S'OutboundHttpDependencyLogger'`, support README history | same revision | historical HTTP dependency logger existed and was later deleted while the support README comparison text remained | history establishes repository evolution, not the motivation behind every deletion unless explicitly recorded in commit/source text |
| EVD-013 | static probes | `evidence/raw/015-adapter-outbound-support-inventory.txt` through `020-adapter-outbound-support-project-edge-usage.txt` | 2026-08-29 | quantified leaf inventory plus required public-reachability, conditional-wiring, duplicate-mechanism, documentation-drift and project-edge-usage searches | textual/static probes do not cover reflection, generated registration, external consumers, or runtime execution unless separately evidenced |
| EVD-014 | runtime probe | `evidence/raw/021a-support-logger-pii-probe.java`, `021-support-logger-pii-probe.txt` | 2026-08-29 | current compiled FailOpenDependencyLogger renders explicit email/body markers present in an exception message into the WARN message | controlled local probe proves logger behavior for supplied exception text; it does not claim a particular real provider currently emits that exact text |
| EVD-015 | runtime probe | `evidence/raw/022a-notification-logger-failure-probe.java`, `022-notification-logger-failure-probe.txt` | 2026-08-29 | current compiled notification consumer calls failure observation after a successful send when success logging throws, and propagates a failure-logging RuntimeException | uses a deliberately throwing SLF4J proxy rather than a real disk-full/appender outage; it isolates the control-flow contract |
| EVD-016 | command | `evidence/raw/023-adapter-outbound-support-test.txt` | 2026-08-29 | fresh `:adapter:outbound:support:test --rerun-tasks` execution succeeds | focused leaf test does not exercise exception-message PII or throwing-logger consumer behavior |
| EVD-017 | command | `evidence/raw/024-adapter-outbound-support-dependencies.txt`, `025-clean-architecture-dependencies.txt` | 2026-08-29 | current support compileClasspath has external Spring/SLF4J dependencies and registry project-edge verification succeeds | dependency verification proves allowed graph shape, not semantic necessity of every consumer edge |
| EVD-018 | command | `evidence/raw/026-messaging-support-consumer-test.txt`, `027-notification-support-consumer-test.txt`, `028-optional-adapter-bean-gating-test.txt` | 2026-08-29 | fresh relevant messaging, notification and optional-adapter composition test classes succeed | selected focused tests do not substitute for exhaustive downstream-module or full deployed-runtime testing |
| EVD-019 | command | `evidence/raw/029-clean-architecture-support-rule.txt` | 2026-08-29 | fresh CleanArchitectureTest execution succeeds with the outbound-peer/support exception rule present | ArchUnit statically verifies bytecode dependency rules; it does not prove runtime activation or logging failure behavior |
| SRC-042 | JPA API code/tests | `src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/api/**`, matching `src/test/**/api/**` | same revision | complete 49-type external API vocabulary plus 6 dedicated tests: bounded operation/query identities, failure algebra, cursor/keyset contracts, transaction/retry/completion evidence | implementation semantics such as actual commit classification, SQLSTATE translation and query observation are owned by later sub-scopes |
| SRC-043 | JPA API consumers/wiring | `src/app-bootstrap/.../jpa/{JpaPlatformAutoConfiguration,JpaPlatformReport,JpaPlatformEndpoint,JpaPlatformRuntimeAutoConfiguration}.java`, persistence `JpaRetryObservation`, `DefaultJpaRetryPolicy`, `FullTransactionRetryCoordinator` | same revision | capability report reaches actuator model, retry reason is not a current metric tag, and API transaction types feed actual retry coordinator | consumer reads are API-meaning traces only; their owning implementation sub-scopes are not thereby complete |
| SRC-044 | JPA API surface/history | `docs/architecture/jpa-api-surface.txt`, `src/build-logic/.../ca.api-surface.gradle`, git history for `SignedJsonCursorCodec`, `CapabilitySupport`, `JpaEntityNotFoundException` | same revision | committed 49-type intended external API surface and history of cursor bound hardening | public-surface baseline governs names, not method behavior or external adopter usage |
| EVD-020 | static probes | `evidence/raw/031-persistence-jpa-module-inventory.txt` through `034-persistence-jpa-api-document-surface-check.txt` | 2026-08-29 | 605-file module denominator and API public-reachability/conditional/duplicate/document-surface probes | static/textual reachability excludes reflection/generated code/external adopters and can over-count same-package Javadoc references |
| EVD-021 | runtime probe | `evidence/raw/035a-jpa-cursor-boundary-probe.java`, `035-jpa-cursor-boundary-probe.txt` | 2026-08-29 | current compiled cursor codec round-trips 2045 bytes but rejects its own encoded tokens at 20462048 bytes while rejecting 2049 at encode | focused codec probe does not exercise HTTP transport or an application-specific cursor payload mapper |
| EVD-022 | runtime probe | `evidence/raw/036a-jpa-api-bound-probe.java`, `036-jpa-api-bound-probe.txt` | 2026-08-29 | constructors accept 100k-character capability constraints/retry reason and `Integer.MAX_VALUE` maxAttempts | records type-level bounds only; current shipped composition does not supply such capability strings and effective retry budget needs transaction trace |
| EVD-023 | command | `evidence/raw/037-persistence-jpa-api-tests.txt`, `038-persistence-jpa-api-surface.txt`, `039-jpa-platform-capability-composition-test.txt` | 2026-08-29 | fresh six-class API tests, public API-surface verification and app-bootstrap capability composition test all BUILD SUCCESSFUL | green existing tests do not contain the 20462048 cursor round-trip boundary property |
| EVD-024 | history | `evidence/raw/040-persistence-jpa-api-history.txt` | 2026-08-29 | cursor pre-decode bounds including `decodedLengthOf` were introduced in commit `2f5d2fc`; capability/entity-not-found types date to initial JPA platform commit | commit diffs show repository evolution but do not establish unstated author intent |
| SRC-045 | JPA transaction/failure code | `src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/{transaction,failure}/**`, matching dedicated tests | same revision | complete 32-production/19-test transaction execution, retry, deadline, completion-evidence and operational-error implementation surface | real database lost-ack semantics and owning vendor translation require cross-scope evidence |
| SRC-046 | JPA transaction composition/docs | `src/app-bootstrap/.../jpa/{JpaPlatformRuntimeAutoConfiguration,JpaTransactionAutoConfiguration}.java`, `PersistenceJpaRootAutoConfiguration.java`, `docs/jpa/{transaction-guide,support-matrix,runbooks}.md` | same revision | canonical `PolicyTransactionPort` implementation differs from public JPA executor/coordinator stack; Stable completion-evidence docs can be compared to actual bean construction | static composition does not itself reproduce a network-level unknown commit |
| EVD-025 | JPA transaction static/runtime verification | `evidence/raw/041-*` through `051-*` | 2026-08-29 | 51-file denominator/reachability/history, custom-policy probe, commit-ambiguity probe, fresh focused transaction tests and app-bootstrap wiring tests | fake transaction managers isolate control flow; they do not prove a real PostgreSQL commit was applied before acknowledgement loss |
| SRC-047 | Hibernate/Spring Data/Querydsl code/tests | `src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/{hibernate,springdata,querydsl}/**`, matching dedicated tests | same revision | complete 42-production/11-test query/batch/stream/fetch/keyset/sort/Querydsl bounded sub-scope | PostgreSQL vendor internals and entire integration source set remain later owning scopes |
| SRC-048 | JPA query architecture/composition | `JpaModuleBoundaryTest.java`, app-bootstrap `CleanArchitectureTest.java`, persistence `build.gradle`/`gradle.lockfile`, `NamedStatementInspector.java` | same revision | package DAG/export rules, Querydsl compile-only/runtime optionality, split export allowlists and missing statement-inspector production wiring | static reachability does not exclude reflection/external adopters and architecture rules do not prove runtime feature invocation |
| SRC-049 | JPA collection-fetch release evidence | `src/config/jpa/release-registry.json`, persistence `build.gradle`, `HibernateCollectionFetchPaginationContractTest.java`, `PostgreSqlQueryPlanContractTest.java`, root `verifyJpaReleaseGateTasks` | same revision | blocking collection-fetch gate maps to a query-plan task selecting a different tag/test class, while target test itself does not inspect generated SQL limit | aggregate release task also runs the jpa-contract lane, so this proves per-gate provenance/assertion weakness rather than absence of all collection tests |
| EVD-026 | focused/architecture verification | `evidence/raw/052-persistence-jpa-hibernate-springdata-querydsl-tests.txt`, `055-persistence-jpa-query-architecture-tests.txt` | 2026-08-29 | fresh 53-file-scope focused tests and package/bootstrap architecture tests BUILD SUCCESSFUL | existing tests omit the newly probed IDENTITY/Specification boundaries and cannot detect split-SSOT semantics |
| EVD-027 | runtime/library probes | `evidence/raw/053-jpa-query-hibernate-boundary-probe.txt`, `061-spring-data-specification-unrestricted-contract.txt` | 2026-08-29 | property-access IDENTITY bypass, one-batch semantic edge, non-null null-predicate Specification acceptance, and Spring Data 4.0.7 unrestricted contract | controlled probes do not show a current production entity/repository actually uses the failing mappings |
| EVD-028 | PostgreSQL/release-gate verification | `evidence/raw/057-persistence-jpa-query-hibernate-postgresql-contracts.txt`, `058-persistence-jpa-queryplan-gate-task.txt`, `059-verify-jpa-release-gate-tasks.txt` | 2026-08-29 | selected real-PostgreSQL batch/ID/collection contracts pass; exact registry task executes only `PostgreSqlQueryPlanContractTest`; task-existence validator still passes | green collection-fetch tests prove current assertions only, not SQL-side pagination |
| EVD-029 | reachability/history/provenance | `evidence/raw/054-persistence-jpa-query-hibernate-reachability.txt`, `056-persistence-jpa-collection-fetch-gate-provenance.txt`, `060-persistence-jpa-query-hibernate-history.txt` | 2026-08-29 | implementation adoption/wiring, release tag mismatch, and historical fixes/initial evidence design are recoverable from raw source/history | git history establishes evolution, not unstated intent |
| SRC-050 | PostgreSQL vendor code/tests/migrations | `src/adapter/outbound/persistence-jpa/src/{main/java,main/resources,test/java}/**/postgresql/**` | same revision | 55 production Java + 9 dedicated unit Java + 9 vendor migrations의 complete owning surface와 SQLSTATE/idempotency/inbox/outbox/native/COPY/type helper 구현 | complete PostgreSQL integration/readiness source set은 sub-scope 11 소유 |
| SRC-051 | PostgreSQL runtime composition | `PostgreSqlPersistenceConfig`, `JpaPlatformRuntimeAutoConfiguration`, `JpaTransactionAutoConfiguration`, `PostgreSqlIdempotencyProviderConfig`, `DefaultJpaRetryPolicy` | same revision | vendor translator가 transaction failure chain에, PostgreSQL Idempotency V2 store가 provider composition에 실제 연결됨 | 모든 profile/deployment가 동일 bean set을 사용한다는 보장은 아님 |
| SRC-052 | reliability contracts/history | `application-core/.../{idempotency,inbox,outbox}/**`, `docs/superpowers/specs/2026-07-28-jpa-production-capability-design.md`, `docs/reviews/2026-08-14-jpa-module-code-review.md` | same revision/current history | replay TTL, owner-safe transition, completion-unknown/reconciliation 기대 계약과 과거 wiring findings를 현재 구현과 비교 | 문서만으로 runtime behavior를 증명하지 않으므로 probes와 교차검증 |
| EVD-030 | real PostgreSQL probe | `evidence/raw/062-postgresql-replay-semantic-probe.txt`, `062a-postgresql-replay-semantic-probe.java` | 2026-08-29 | same-store inbox forged-owner replay와 changed-retention, polling outbox changed-schedule replay를 PostgreSQL 16.15에서 재현 | 해당 inbox/outbox adapters는 현재 default production composition에서 확인되지 않은 candidate |
| EVD-031 | translator/policy probes | `evidence/raw/063-postgresql-40003-probe.txt`, `069-postgresql-40003-policy-probe.txt` | 2026-08-29 | SQLSTATE 40003이 UNKNOWN/completionUnknown=false가 되고 실제 DefaultJpaRetryPolicy에서 RECONCILE가 아니라 FAIL로 결정됨 | synthetic SQLException 40003; 실제 network commit acknowledgement loss 자체를 재현한 것은 아님 |
| EVD-032 | codec probe | `evidence/raw/065-pg-range-escaped-quote-probe.txt`, `065a-pg-range-escaped-quote-probe.java` | 2026-08-29 | current PgRangeCodec의 escaped quote/backslash endpoint self-round-trip 실패 | pure codec probe; real PostgreSQL text output/provider consumer는 실행하지 않음 |
| EVD-033 | real PostgreSQL idempotency probe | `evidence/raw/066-postgresql-idempotency-replay-boundary-probe.txt`, `066a-postgresql-idempotency-replay-boundary-probe.java` | 2026-08-29 | changed replayTtl false-same completion과 expired COMPLETED inspect/claim lifecycle divergence를 production store + PostgreSQL 16에서 재현 | temporary analysis tests; 실행 후 repository source에서 제거/복원 |
| EVD-034 | command | `evidence/raw/067-persistence-jpa-postgresql-unit-tests.txt` | 2026-08-29 | 9 dedicated PostgreSQL unit classes fresh `--rerun-tasks` BUILD SUCCESSFUL | existing assertions가 새 replay/expiry/range/40003 policy boundaries를 포함하지 않음 |
| EVD-035 | reachability/history | `evidence/raw/064-postgresql-vendor-manifest-reachability.txt`, `068-postgresql-vendor-history-review-provenance.txt` | 2026-08-29 | 73-file denominator, key production construction, current history와 prior-review exact-term provenance | static reachability는 reflection/external adopter/runtime activation을 완전히 증명하지 않음 |
| SRC-053 | JPA baseline capability code/tests/migrations | `evidence/raw/070-persistence-jpa-baseline-capability-manifest.txt`, baseline `audit/auditing/cache/envers/h2/idempotency/liveevent/lock/migration/observation/operation/outbox/security/config` sources | same revision | 61 production + 19 dedicated test + 7 migration SQL, 87/87 FULL_READ | complete PostgreSQL integration lane belongs to sub-scope 11 |
| SRC-054 | baseline composition/security provenance | `evidence/raw/072-baseline-capability-reachability.txt`, `JpaAdapterComponentsConfig`, `JpaPlatformRuntimeAutoConfiguration`, `JpaPlatformReport`, `docs/jpa/security.md` | same revision | outbox is baseline-composed, liveevent/durable adapters are not; runtime-role Stable contract promises startup fail-fast but production never invokes `requireSafe`, and report only checks CREATE privilege | static caller search does not cover external applications constructing these public types themselves |
| EVD-036 | real PostgreSQL probe | `evidence/raw/071-liveevent-full-sweep-probe-output.txt`, `071a-liveevent-full-sweep-probe.java` | 2026-08-29 | after a stream is fully swept, current-row `max(position)` becomes null and allocator reuses position 1 on PostgreSQL 16 | temporary analysis test; adapter is currently not default-composed |
| EVD-037 | real PostgreSQL probe | `evidence/raw/073-durable-operation-expired-lease-output.txt`, `073a-durable-operation-expired-lease-probe.java` | 2026-08-29 | expired lease owner can still update RUNNING operation to SUCCEEDED before takeover because terminal update lacks lease-expiry predicate | temporary analysis test; adapter is currently not default-composed |
| EVD-038 | focused adapter probe | `evidence/raw/075-outbox-stale-worker-state-regression-output.txt`, `075a-outbox-stale-worker-state-regression-probe.java` | 2026-08-29 | baseline outbox `markFailed` can regress a PUBLISHED entity to FAILED with no owner/attempt/state CAS fencing | focused unit-level transition probe; multi-worker database timing itself is inferred from separately committed claim/relay transaction structure |
| EVD-039 | command | `evidence/raw/076-persistence-jpa-baseline-unit-tests.txt` | 2026-08-29 | fresh full `:adapter:outbound:persistence-jpa:test --rerun-tasks` BUILD SUCCESSFUL, 18 actionable tasks executed | unit lane does not replace real-PostgreSQL semantics, which are separately probed where required |
| SRC-055 | Fileserver persistence + migrations | `evidence/raw/077-persistence-jpa-fileserver-manifest.txt`, `src/adapter/outbound/persistence-jpa/src/main/{java,resources}/**/fileserver/**` | same revision | 25 production Java + 4 migration SQL, 29/29 FULL_READ; capability is opt-in but production-composed when enabled | PostgreSQL integration/readiness source denominator remains sub-scope 11 |
| SRC-056 | Fileserver quota/composition/schema contracts | `evidence/raw/079-fileserver-reachability-quota-schema-contract.txt`, application Fileserver quota/admission code, Fileserver schema activation, design deviations/plan | same revision | production quota aggregate readers/byte ceiling are absent; V3/V4 schema changes are not represented in registry revision while activation accepts >=2 | static cross-scope search cannot prove behavior of external adopters outside this repository |
| EVD-040 | real PostgreSQL probe | `evidence/raw/078-fileserver-quota-boundary-probe-output.txt`, `078a-fileserver-quota-boundary-probe.java` | 2026-08-29 | expired direct reservation still commits; reclaim request spanning 65 one-byte committed rows leaves 1 byte because only 64 rows are loaded | temporary analysis tests added to Fileserver reclamation class and restored after run |
| EVD-041 | real PostgreSQL concurrency probe | `evidence/raw/080-fileserver-recovery-concurrent-enqueue-output.txt`, `080a-fileserver-recovery-concurrent-enqueue-probe.java` | 2026-08-29 | two simultaneous first enqueue calls for one file produce one success + one DataIntegrityViolationException, with one row retained | scheduling is barrier-assisted but exact winner is nondeterministic as expected |
| EVD-042 | real PostgreSQL migration probe | `evidence/raw/081-fileserver-schema-activation-v2-output.txt`, `081a-fileserver-schema-activation-v2-probe.java` | 2026-08-29 | Fileserver Flyway target 2 promoted ACTIVE passes `FileserverSchemaActivation` while V3 claim_token and V4 lifecycle_state columns are absent | demonstrates gate false-positive; full Spring context with `ddl-auto=none` was not separately booted |
| EVD-043 | command | `evidence/raw/082-fileserver-official-readiness-lanes.txt` | 2026-08-29 | original-source Fileserver migration/metadata/reclamation PostgreSQL readiness tasks fresh `--rerun-tasks` BUILD SUCCESSFUL, 21 actionable tasks executed, git clean before/after | these official assertions do not include the temporary boundary probes, which are captured separately |
| EVD-044 | real PostgreSQL liveness probe | `evidence/raw/079-fileserver-cleanup-crash-budget-output.txt`, `079a-fileserver-cleanup-crash-budget-probe.java` | 2026-08-29 | Fileserver cleanup의 declared max attempt 8을 넘겨 crash-reclaim만으로 attempt 9가 되고도 row가 `FAILED` / `CLAIM_LEASE_EXPIRED`로 다시 claim 가능함을 재현 | controlled repeated lease-expiry simulation; physical storage crash 자체를 발생시킨 것은 아니며 probe 종료 후 analysis-owned test source는 exact HEAD blob으로 복구됨 |
| SRC-057 | Notification persistence + migrations | `evidence/raw/083-persistence-jpa-notification-manifest.txt`, `src/adapter/outbound/persistence-jpa/src/main/{java,resources}/**/notification/**` + 5 dedicated unit tests | same revision | 53 production Java + 10 migrations + 5 unit Java, 68/68 FULL_READ; request/recipient/attempt/admin/reconciliation/provider-event/inbox persistence and opt-in composition | full PostgreSQL integration/readiness denominator remains sub-scope 11 |
| SRC-058 | Notification runtime reachability/contracts | `evidence/raw/092-notification-reachability-test-gap.txt`, `NotificationDispatchService`, `DispatchOutcomeRecorder`, `ReconciliationJobWorker`, `NotificationAdminApplicationService` | same revision | post-provider recorder uses lease-unaware save, reconciliation processing is outside durable claim, admin atomic claim has no production caller, V4 is final registry revision write | static call graph is repository-internal and does not cover external adopters |
| EVD-045 | real PostgreSQL schema probe | `evidence/raw/084-notification-schema-v4-activation-probe.txt` | 2026-08-29 | V4-only ACTIVE database passes activation count while current-required expires/projection/collapse/admin/evidence columns are absent | full Spring context boot was not required to demonstrate gate predicate false-positive |
| EVD-046 | real PostgreSQL lease probes | `evidence/raw/085-notification-expired-lease-write-probe.txt`, `091-notification-stale-provider-overwrite-probe.txt` | 2026-08-29 | expired holder is not still-held yet owner+fence update succeeds; after worker B takeover an ID-only stale projection overwrites lifecycle while preserving B/fence 8 | SQL reproduces exact predicates/effect; provider network call itself is not simulated |
| EVD-047 | real PostgreSQL reconciliation probe | `evidence/raw/086-notification-reconciliation-claim-probe.txt` | 2026-08-29 | two sequential autocommit `FOR UPDATE SKIP LOCKED` claims return the same due job before any complete/reschedule, proving select-lock lifetime does not cover worker processing | controlled two-session semantics; provider status query itself is not executed |
| EVD-048 | admin claim/reachability probe | `evidence/raw/087-notification-admin-claim-completion-probe.txt`, `088-notification-admin-claim-reachability.txt` | 2026-08-29 | atomic claim row cannot be completed by current save-style duplicate insert, and production `operations.claim()` call sites are zero while find→action→save remains | direct SQL + static repository call graph |
| EVD-049 | fresh official Notification verification | `evidence/raw/089-notification-schema-official-readiness.txt`, `090-notification-existing-contracts-fresh.txt` | 2026-08-29 | schema readiness and existing recipient/admin claim contracts both BUILD SUCCESSFUL with `--rerun-tasks`, 19/19 tasks each | green tests validate existing assertions; they omit current-schema compatibility, post-provider lease write, reconciliation claim lifetime, and production admin claim wiring |
| SRC-059 | Experimental platform code/tests/migration | `evidence/raw/093-persistence-jpa-experimental-manifest.txt`, `src/adapter/outbound/persistence-jpa/src/main/java/**/experimental/**`, dedicated unit tests, `db/experimental-rls/V1__tenant_rls.sql` | same revision | 29 production + 8 unit + 1 SQL의 38/38 owning FULL_READ와 multi-tenancy/RLS/schema/database tenancy/read-replica/next-compatibility surface | 현재 app-bootstrap production wiring은 확인되지 않아 semantic defects는 latent로 분류 |
| SRC-060 | Experimental composition/consent | `evidence/raw/096-experimental-gate-reachability.txt`, `099-experimental-structural-optin-gap.txt`, `ExperimentalEntryConsentTest`, `PersistenceJpaConfig`, `JpaModuleBoundaryTest` | same revision | 일부 activation-capable public constructor가 gate list 밖에 있고 Stable entity/repository scan 문자열이 experimental package를 포함하지만 현재 experimental JPA stereotype은 0 | external consumers/reflection까지 증명하지 않으며 현재 repository production caller는 0 |
| EVD-050 | focused semantic probes | `evidence/raw/095-experimental-pool-overshoot-probe.txt`, `097-experimental-replica-provider-probe.txt` | 2026-08-29 | heterogeneous pool 8+5가 max 10을 넘어 13으로 열림; no-evidence EVENTUAL read가 REPLICA; unknown Hibernate 9가 Stable replacement 허용됨 | analysis-only temporary unit tests; source는 실행 후 복원 |
| EVD-051 | real PostgreSQL security probe | `evidence/raw/098-experimental-rls-missing-table-probe.txt` | 2026-08-29 | PostgreSQL 16에서 RLS verifier가 requested missing tenant table을 exception 없이 성공으로 인정 | current app runtime does not compose RLS verifier; demonstrates verifier contract only |
| EVD-052 | fresh original Experimental verification | `evidence/raw/100-experimental-original-unit-tests.txt`, `101-experimental-original-postgresql-contracts.txt` | 2026-08-29 | original 8 experimental unit + boundary/scan tests and 5 PostgreSQL contract/migration/security classes all BUILD SUCCESSFUL; git clean before/after | existing green assertions omit the newly probed missing-table, partial pool headroom, no-evidence EVENTUAL, unknown-major and exhaustive opt-in boundaries |
| SRC-061 | JPA testkit + fixture/unit corpus | `evidence/raw/102-persistence-jpa-testkit-manifest.txt`, `src/adapter/outbound/persistence-jpa/src/testkit/java/**`, `src/adapter/outbound/persistence-jpa/src/test/java/**/testkit/**` | same revision | 41 testkit + 21 fixture/unit Java, 62/62 FULL_READ; architecture/query-plan/release/migration/failure/pool helper semantics | production persistence behavior 자체가 아니라 evidence producer의 정확성을 분석 |
| EVD-053 | testkit semantic false-negative probes | `evidence/raw/103-testkit-unit-boundary-probes.txt` | 2026-08-29 | `CompletableFuture<Entity>` architecture leak accepted; audit decoy parameter accepted; nested child estimate 1000x miss가 ratio 1.0으로 축약; UUID test fixture same-ms inversion 3784에서 재현 | UUID helper는 exact FQN consumer 0이라 production defect로 승격하지 않음 |
| EVD-054 | real PostgreSQL EXPLAIN side-effect probe | `evidence/raw/104-testkit-explain-dml-cte-probe.txt` | 2026-08-29 | SELECT-only guard가 data-modifying CTE를 허용해 `EXPLAIN ANALYZE` 후 row `bucket 9 -> 99`; PostgreSQL 16 BUILD SUCCESSFUL | current committed query-plan inputs는 SELECT이므로 current release mutation을 주장하지 않음 |
| EVD-055 | testkit reachability sweep | `evidence/raw/105-testkit-public-reachability-sweep.txt` | 2026-08-29 | production/release-connected helpers와 zero-reference `CommitAmbiguityProxy`, `PostgreSqlContractExtension` 구분 | simple-name collision은 exact FQN 추가 확인으로 보정 |
| EVD-056 | fresh original testkit evidence | `evidence/raw/106-testkit-original-verification.txt` | 2026-08-29 | JPA full unit 29s green, production JPA architecture 1m47s green, original PostgreSQL query-plan 25s green; git clean before/after | green suite가 newly probed wrapper/CTE/child-plan/substring boundaries를 포함하지 않음 |
| SRC-062 | governance / build / config | `evidence/raw/107-persistence-jpa-governance-manifest.txt`, `adapter/outbound/persistence-jpa/{CLAUDE.md,README.md,build.gradle,gradle.lockfile}`, `config/**`, `JpaModuleBoundaryTest`, `CandidateAdapterCompositionTest` | same revision | leaf 최상위 4 + production 4 + test 3 = 11/11 FULL_READ; strictTestLanes/testkitPublisher/apiSurface 계약, 24-package catalog와 export list, always-install 대 opt-in scan 경계 | sub-scope 06이 이미 계상한 config/platform test 3개는 여기서 재계상하지 않으며, 그 test의 내용 분석만 이 sub-scope가 수행 |
| SRC-063 | composition reachability | `evidence/raw/108-governance-config-reachability.txt`, `PersistenceJpaRootAutoConfiguration`, `CaSkeletonApplication`, `PostgreSqlPersistenceConfig`, `H2PersistenceConfig`, `PersistenceVendorProdSafetyValidator` | same revision | `config` public type 3개의 leaf 밖 소비자 존재; leaf `@ConfigurationProperties` 3형제 중 `PersistenceVendorSettings`만 production enablement 부재; composition root `@ConfigurationPropertiesScan`이 persistence tree를 덮지 않음 | 정적 검색은 reflection/외부 adopter를 덮지 않는다; prod safety validator는 `h2` 값만 거부하므로 unknown 값 검증과 무관 |
| EVD-057 | 실행 probe | `evidence/raw/109-vendor-selector-shipped-shape-probe.txt`, `109a-vendor-selector-shipped-shape-probe.java` | 2026-08-29 | shipped 모양 + `vendor=mysql`에서 context 성공·settings bean 0·SPI bean 0·양 vendor config 0; `@EnableConfigurationProperties` 추가 시 property를 지목하는 `ConfigurationPropertiesBindException`; component scan 포함 case의 실패 메시지에 vendor property 부재 | `ApplicationContextRunner` context이지 full application context가 아니므로 실제 배포에서 최초로 실패하는 bean은 다를 수 있음; 임시 test는 실행 후 삭제하고 git clean 확인 |
| SRC-064 | documentation / count drift | `evidence/raw/110-governance-doc-count-drift.txt`, `src/build.gradle:verifyDocumentedLeafCount`, `docs/jpa/repository-adaptation.md`, `docs/architecture/jpa-api-surface.txt`, `JpaModuleBoundaryTest`, `CleanArchitectureTest`, leaf `README.md` | same revision | registry 44 대 문서/주석의 19-leaf 6곳; public top-level type 338/350 대 주석의 318/324; README의 package root·module 이름 drift; gate 탐색 domain이 `CLAUDE.md`/`build.gradle` 두 파일명뿐 | drift는 문서·주석에 한정되며 런타임 동작에 영향 없음; gate 자체는 green으로 통과함을 별도 실행으로 확인 |
| SRC-065 | pool lane | `evidence/raw/111-persistence-jpa-pool-lane-manifest.txt`, `112-pool-lane-claim-registry-reachability.txt`, `src/jpaPlatformPerformanceTest/**`, `config/jpa/release-registry.json`, `docs/jpa/support-matrix.md`, `.github/workflows/jpa-nightly.yml` | same revision | 3/3 FULL_READ; release registry gate 6개에 pool lane 부재(3곳 모두 exit=1)이나 `jpaPlatformReleaseGate`는 의존; lane assertion 8개 중 2개가 공식 항등식이고 pending 관측 assertion 부재 | `verifyJpaReleaseGateTasks`는 registry→task 한 방향만 검사하므로 역방향 미검증 사실은 정적 관찰 |
| EVD-058 | 실제 PostgreSQL probe | `evidence/raw/113-pool-lane-saturation-probe.txt`, `113a-pool-lane-saturation-probe.java` | 2026-08-29 | 실제 포화 Hikari pool에서 active=2/idle=0/pending=1/saturated=true, 반납 후 대기자 획득; acquisition 실측 504ms 대 설정 500ms 대 assertion 상한 2,500ms | 단일 머신 관측이며 성능 수치가 아니라 계약 관측; 임시 test는 실행 후 삭제하고 git clean 확인 |
| EVD-059 | fresh original verification | `evidence/raw/114-governance-pool-original-verification.txt` | 2026-08-29 | 원본 소스에서 leaf unit lane 28s green(18 executed), `jpaPlatformPoolContractTest` 24s green(18 executed), root `verifyDocumentedLeafCount` 3s green(9 executed), git clean before/after | green은 기존 assertion의 통과를 뜻하며 §119·§125가 지적한 미검증 영역을 포함하지 않는다 |
| SRC-066 | integration/readiness lane corpus | `evidence/raw/120-persistence-jpa-integration-lane-manifest.txt`, `src/postgresqlIntegrationTest/**` | same revision | 75/75 FULL_READ(71 Java + 4 SQL, 13,977 lines); tag 5종 분포, 무-tag 클래스 13개와 readiness task 14개의 1:1 대응, orphan test 0 | 파일 소유는 이 sub-scope이나 §52(collection-fetch)·sub-scope 10(explain runner) 등 이미 판정된 결함은 중복 계상하지 않음 |
| SRC-067 | evidence 배선(card ↔ lane ↔ gate) | `config/jpa/readiness-cards.yaml`, `src/gradle/jpa-evidence.gradle`, `config/jpa/release-registry.json`, `.github/workflows/{ci-quality-gates,jpa-nightly,jpa-pr,jpa-release,jpa-r2-evidence}.yml` | same revision | card 17개 중 active 13, producer 12; card scenario가 가리키는 클래스 12개는 전부 `readiness/**`이고 `platform/**` 33개는 0개; readiness task는 `jpaPlatformReleaseGate`에 없고 workflow가 직접 부르지도 않음 | 배선은 `--dry-run` task graph resolve로 확인했으며, CI 실제 실행 이력은 이 저장소 안에서 확인할 수 없다 |
| EVD-060 | command | `evidence/raw/115-integration-lane-original-verification.txt` | 2026-08-29 | 원본 소스에서 5개 tag lane `--rerun-tasks` BUILD SUCCESSFUL in 3m 10s — 51 classes / 244 tests / 0 skipped / 0 failures / PostgreSQL 컨테이너 87회 기동, git clean before/after | 같은 실행에 이어 붙인 `verifyJpaCandidateEvidence``:app-bootstrap:test`의 compose scenario가 `jq` 부재로 실패해 완주하지 못했다(환경 제약, app-bootstrap 소유) |
| EVD-061 | command | `evidence/raw/116-readiness-lane-original-verification.txt`, `118-readiness-task-result-matrix.txt` | 2026-08-29 | 14개 readiness task `--rerun-tasks --continue` 결과 표: 82 tests / 0 skipped / 12 PASS / 2 FAIL, git clean before/after | `postgresqlSecurityBaselineIntegrationTest`의 실패는 인증서 SAN이 `localhost` 단일이라 형제 컨테이너 환경에서 매핑 포트에 닿지 못한 환경 제약이며 repository 결함이 아니다 |
| EVD-062 | 실패 재현 + history | `evidence/raw/117-flyway-migration-readiness-lane-failure.txt` | 2026-08-29 | `postgresqlMigrationIntegrationTest` 단독 `--rerun-tasks` BUILD FAILED/exit 1, 두 assertion 실패 원문(`1,3,4,5,6,9,10,11,12``1,3,4,5,6`; `1,2``1`), stream 파일 목록, assertion 최종 수정 2026-07-31 대 migration 추가 08-15/08-18/08-28 | 원본 unmodified source, git clean before/after; CI가 현재 red인지 여부는 저장소 안에서 확인할 수 없고 확인된 것은 이 revision에서 task가 실패한다는 사실이다 |
| EVD-063 | 실제 PostgreSQL probe | `evidence/raw/119-notification-migration-ladder-probe.txt`, `119a-notification-migration-ladder-probe.java` | 2026-08-29 | notification 사다리 4종의 컬럼 집합 실측: V1V10 218, V1V9 218(차 0), V1V8 213(차 5), V1V6 208(차 10)과 누락 컬럼 이름 전체 | 컬럼 집합 비교이며 데이터·제약 semantics 비교가 아니다; V10이 DDL 없는 guard이기 때문에 V9와 V10의 컬럼 수가 같다 |
| SRC-068 | cross-scope 정합 | `HibernateCollectionFetchPaginationContractTest`, `PostgreSqlQueryPlanContractTest`, `PostgreSqlSecurityContractTest`, `TenantPoolCapacityContractTest`, `AdminOperationClaimContractTest` | same revision | 앞선 sub-scope 04·06·08·09·10의 결함이 이 lane에서 green으로 남은 이유를 각 test의 assertion 범위로 설명(SQL limit 미확인, CTE 미포함, test가 만든 role/policy, 균일 pool 크기, test가 재작성한 claim SQL) | 정합 설명이며 새 결함 판정이 아니다 |
| SRC-069 | module map / denominator | `evidence/raw/121-persistence-mongo-module-inventory.txt`, `src/adapter/outbound/persistence-mongo/**` | same revision | mongo leaf 497 tracked files(main 353 / test 104 / testkit 35 / perf 1 / top-level 4), 약 38.5k LOC, production Java 351, package 지도, 선언된 8개 test lane | 초기 sizing이며 각 sub-scope의 최종 denominator는 그 sub-scope manifest가 확정한다 |
| SRC-070 | governance / opt-in scope | `evidence/raw/122-mongo-governance-optin-manifest.txt`, mongo `CLAUDE.md`/`README.md`/`build.gradle`/`gradle.lockfile`, root package 4, `autoconfigure/**` 9, `META-INF` 등록 resource 2, 관련 test 12 | same revision | 31/31 FULL_READ; opt-in 네 겹(import filter → root auto-config → persistence config → platform/observability auto-config)과 각 겹이 막는 실패, startup validator/probe requirement 배치 | 이 sub-scope의 도달성은 Java import graph가 아니라 등록 metadata와 annotation 인자에 있어 정적 참조 검색만으로 판단할 수 없다 |
| SRC-071 | opt-in reachability / sibling / duplicate | `evidence/raw/123-mongo-optin-reachability-and-siblings.txt`, `CapabilityDependencyValidator`, `CapabilityDependencyStartupCheck`, `application.yml:370` | same revision | root/autoconfigure public type 13개 중 leaf 밖 참조는 2개; master switch를 읽는 production 지점 6곳이 조건 동일; `ca-skeleton.persistence-mongo.*` namespace의 네 번째 key `active-profile`만 소유자가 leaf 밖 | 정적 검색은 reflection·생성 등록·저장소 밖 adopter를 덮지 않는다 |
| EVD-064 | 실행 probe | `evidence/raw/124-mongo-platform-settings-binding-probe.txt`, `124a-mongo-platform-settings-binding-probe.java` | 2026-08-29 | `change-streams=true` → 예외 없이 bound value false; `transactions=true` → true 보존; `required-secondaries=-1``MongoOperationRejectedException`으로 context 실패 | binding 계층만 관측했고 change stream 실행체 자체는 이 저장소에 shipped되지 않는다; 임시 test는 실행 후 삭제하고 git clean 확인 |
| SRC-072 | documentation / count drift | `evidence/raw/125-mongo-governance-doc-count-drift.txt`, mongo `build.gradle`, `docs/architecture/mongo-api-surface.txt`, `MongoNamespaceContractTest`, `MongoModuleBoundaryTest`, `docs/mongodb/repository-adaptation.md`, `docs/adr/ADR-MONGO-001` | same revision | build.gradle 주석의 311/313 대 실측 346/351, 382 대 실측 526; namespace guard의 domain(`src/main/**`)과 그 밖에 생존한 폐기 키 3+2곳; 19-leaf claim 3곳 대 registry 44; README "10개 규칙"은 방향 규칙 개수로 정확 | drift는 주석·문서에 한정되며 런타임 동작에 영향 없음; 관련 gate는 모두 green임을 별도 실행으로 확인 |
| EVD-065 | fresh original verification | `evidence/raw/126-mongo-hermetic-lane-original-verification.txt` | 2026-08-29 | 원본 소스 `--rerun-tasks`: unit lane 14 classes/72 tests, stable contract lane 83 classes/526 tests, 둘 다 0 skipped/0 failures; `verifyMongoTestLaneDisjointness`·`verifyMongoReleaseContractLanes`·`verifyMongoApiSurface` 통과; `:app-bootstrap:test --tests *CapabilityDependencyValidatorTest*` 통과; git clean before/after | hermetic lane만 실행했고 Docker 기반 6개 lane(replicaSet/failover/migration/compatibility/security/performance)은 이 실행에 포함되지 않는다 |
| SRC-073 | api core contract | `evidence/raw/127-mongo-api-scope-manifest.txt`, `adapter/outbound/persistence-mongo/src/main/java/**/api/**` + 전용 test 9 | same revision | 70/70 FULL_READ(61 production 2,687 LOC + 9 test); operation identity·실행 context·실패 algebra·BSON 표현 manifest·consistency registry·schema version 정책·관측 seam; committed public surface 346 중 api 기여 59 | `api`는 의도된 외부 표면이라 저장소 내부 참조 0이 dead를 뜻하지 않으며, 저장소 밖 adopter는 정적 검색으로 증명되지 않는다 |
| SRC-074 | api negative-space probes | `evidence/raw/128-mongo-api-negative-space-probes.txt`, `MongoFailureContext`, `MongoTransaction*Exception`, `MongoSchemaVersionPolicy`, `DefaultMongoFailureTranslator`, `MongoConsistencyDescriptor`, `Database/CollectionProfileName` | same revision | framework-free 규칙 소스 전수 검색 매치 0; schema-version 예외 두 생성 경로의 category/버전 비대칭; `MongoTimeoutException` 2-arg 생성자의 `initCause`와 그 규칙을 검사하는 test의 대상 불일치; invariant를 강제하는 타입과 강제하지 않는 타입 6종 비교; 두 profile-name record의 검증 코드 동일성 | 정적 판정이며 실행 probe를 필요로 하지 않았다; production 경로의 정합성(classification 파생)은 코드 경로 추적으로 확인했고 런타임 실행으로 재확인하지는 않았다 |
| EVD-066 | 실행 probe | `evidence/raw/129-mongo-empty-type-registry-write-probe.txt`, `129a-...java` | 2026-08-29 | 빈 type registry로 `MappingMongoConverter.write(...)``IllegalStateException: no type metadata policy is registered for …`; Spring 기본 mapper는 같은 입력에서 `_class` 포함 3키를 씀; `policyFor``CLASS_METADATA_ALLOWED`, `writeTypeRestrictions``_class`를 쓰고 `writeType`은 던진다 | 단일 converter 경로만 관측했고 repository·template 상위 경로 전체를 실행하지 않았다; 임시 test는 실행 후 삭제하고 git clean 확인 |
| SRC-075 | mapping / nativecap / geo | `evidence/raw/130-mongo-mapping-nativecap-geo-manifest-and-probes.txt` | same revision | 27/27 FULL_READ; BSON 표현 manifest의 converter 등록 경로, native capability gateway의 노출 규칙, geospatial operations의 sphere-index 요구; reachability·조건부 형제·중복 mechanism probe | 정적 판정 중심이며 geo 경로는 실제 2dsphere index를 가진 서버에서 재확인하지 않았다 |
| SRC-076 | imperative / reactive 실행 경로 | `evidence/raw/131-mongo-execution-paths-manifest-and-probes.txt` | same revision | 61/61 FULL_READ; 두 executor의 관측·실패번역·deadline 처리와 collection profile registry 경유 규칙; deadline 미부착 지점과 실행 scope 이탈 경로 식별 | 두 executor의 배선은 auto-configuration 정적 판독으로 확인했고 런타임 컨텍스트로 재확인하지 않았다 |
| SRC-077 | query / aggregation | `evidence/raw/132-mongo-query-aggregation-manifest-and-probes.txt` | same revision | 29/29 FULL_READ; allowlist 기반 query 표현 불가능성, keyset cursor HMAC·타입태그·길이 프레이밍; 배선된 bean은 `MongoBudgetEnforcer` 하나이고 그 소비자도 미배선; aggregation executor가 collection을 `String`으로 받아 registry·실행 scope를 우회 | 두 finding 모두 정적으로 결정 가능해 실행 probe를 돌리지 않았다; 미배선이므로 현재 노출은 없다 |
| SRC-078 | transaction / retry / session | `evidence/raw/133-mongo-transaction-manifest-and-probes.txt` | same revision | 27/27 FULL_READ; body 재시도와 commit 재시도의 두 루프 분리를 blocking·reactive 양쪽에서 코드로 추적; transaction subsystem bean 0·cross-package 참조 0인데 `platform.transactions=true`는 startup에서 TRANSACTION capability를 요구 | 미배선 판정은 이 leaf 안의 정적 검색 결과이며 저장소 밖 adopter는 덮지 않는다 |
| SRC-079 | schema / migration | `evidence/raw/134-mongo-schema-migration-manifest-and-probes.txt` | same revision | 58/58 FULL_READ; manifest 기반 선언과 D4 apply 사다리, migration lease의 fencing token 설계; apply policy·diff engine·TTL validator의 production 소비자 0; `mongoMigrationTest` lane 1 class/8 tests/0 failures | apply policy 계층의 미배선은 이 leaf 범위의 검색 결과다; ledger의 `ensureIndexes` 전제는 운영 배포 시점에만 확인 가능하다 |
| EVD-067 | 실행 probe | `evidence/raw/134a-mongo-schema-migration-execution-probes.txt` | 2026-08-30 | 실서버(MongoDB 8.0 replica set): `saveCheckpoint(fence=1 over stored 5)` REFUSED / `recordApplied(fence=1 over stored 5)` **ACCEPTED** → 밀려난 runner가 ledger를 차지하고 live runner는 driver duplicate-key를 받음; hermetic: TTL·sparse·partial·collation 변경과 서버-숨김 index가 전부 `diff.isClean()=true`; `MongoIndexManifest.expireAfter(1s)` 생성 성공; Flamingock lease로 non-resumable migration도 REFUSED | ledger 경로만 직접 호출했고 `MongoMigrationRunner.applyOne`의 인접 `lock.refresh` 보호는 별도로 코드로 확인했다; 임시 test 2개는 실행 후 삭제하고 git clean 확인 |
| SRC-080 | changestream | `evidence/raw/135-mongo-changestream-manifest-and-probes.txt` | same revision | 26/26 FULL_READ; source bean은 무조건·consumer bean은 fork의 5종 SPI에 조건부로 **실제 조립됨**; `changeStreams` flag는 `false` 고정이라 startup CHANGE_STREAM 검사 도달 불가; recovery의 네 결정 메서드 중 하나만 사용되고 `MongoChangeHistoryLostException`은 어디에서도 생성되지 않음; 세 기존 test가 "본 적 있지만 완료되지 않은 위치"를 다루지 않는 이유 | SPI 구현은 전부 test fixture이며 실제 fork 배선을 관측한 것은 아니다 |
| EVD-068 | 실행 probe | `evidence/raw/135a-mongo-changestream-execution-probes.txt` | 2026-08-30 | auto-configuration과 동일 조립으로 3종: (C) worker 1개·failover 중 투영 취소 → 재전달 이벤트가 pipeline에 삼켜지고 checkpoint가 그것을 지나침, state=RUNNING·runbook 빈칸·Flux 정상 완료; (A) BUSY+resumable 실패에서 동일 소실; (B) 실패 없이도 후속 이벤트가 `CLAIMED_ELSEWHERE` 위치를 지나침; (D) `requireCorrectResumeOption`은 자기 자신과 비교 | reactor 기반 hermetic 재현이며 실제 서버의 change stream 재전달 순서를 관측한 것은 아니다(재전달 대상은 stored checkpoint 기준으로 구성); 임시 test 2개는 실행 후 삭제하고 git clean 확인 |
| SRC-081 | security / failure / observation / client | `evidence/raw/136-mongo-security-failure-observation-client-probes.txt` | same revision | 44/44 FULL_READ; `failure`는 완전 배선(classifier·translator bean, 두 executor가 사용), `security` 검증 경로는 `MongoStartupValidator`가 실행, `observation`은 driver 리스너만 customizer로 설치, `client`는 저장소 전체 호출자 0; allowlist 강제·redactor `describe`·잔여 API 4종의 production 호출 0 | 저장소 밖 adopter가 `MongoClientSettingsFactory`를 쓰는 경우는 정적 검색으로 배제할 수 없다 |
| EVD-069 | 실행 probe | `evidence/raw/136a-mongo-client-settings-execution-probe.txt` | 2026-08-30 | `MongoSecurityProfile.production(tls=true, auth=true)`를 validator가 ACCEPTED; Boot가 README의 `spring.data.mongodb.uri`에서 만드는 설정은 `sslEnabled=false`, connect 10000ms, serverSelection 30000ms, poolMaxSize 100, `serverApi=null`, `uuidRepresentation=UNSPECIFIED`; factory가 만들었다면 `sslEnabled=true` | 실제 Spring 컨텍스트가 아니라 Boot가 사용하는 동일 API로 재구성한 비교다; 임시 test는 실행 후 삭제하고 git clean 확인 |
| SRC-082 | advanced 전체 | `evidence/raw/137-mongo-advanced-manifest-and-probes.txt` | same revision | 75/75 FULL_READ; guard bean은 auto-load되지 않는 `MongoAdvancedConfiguration`에만 있어 기본 배선에서 모든 entry point 도달 불가(설계와 일치); 구체 클래스 19개 = entry point 7 + policy 11 + 의도적 제외 1(`@Configuration`); 실행 probe: 모든 승인 증거를 갖춘 입력에서 sharding 4작업 중 1개만 실행(3개는 5인자 `execute``approval=null`로 거부); promotion 증거 어휘 2종·checkpoint 작성자 2곳·Scaffold 고지 누락 1건 | 임시 probe test는 실행 후 삭제하고 git clean 확인; Advanced 능력의 실제 동작은 해당 토폴로지가 없어 검증 불가 |
| SRC-083 | testkit / release / lanes | `evidence/raw/138-mongo-testkit-release-lanes-probes.txt` | same revision | 49/49 FULL_READ; testkit 33종 소비자 계수에서 `MongoRoundTripContract`·`MongoAtlasLocalContainer`·`MongoChunkMigrationController` 0; `MongoStableContractSuite``(not executed)` 분기와 `certified()` 커버리지 검사가 구조적으로 도달 불가(형제 `MongoChaosGate`는 정상); `release-contracts.json`의 차단 계약 3개가 전부 `topology=none` hermetic이고 experimental 3개는 등록되지 않은 task를 가리킴; `.github/workflows` 26개 중 mongo 언급 0(JPA는 7개) | CI 부재는 이 저장소의 workflow 파일 기준이며 외부 파이프라인은 관측 범위 밖이다 |
| SRC-084 | module map / denominator | `evidence/raw/139-identifier-module-inventory.txt`, `src/adapter/outbound/identifier/**` | same revision | leaf 전체 10 tracked files(main Java 4 / test Java 1 / test Groovy 1 / governance 4), 562 LOC; 단일 패키지 `dev.caskeleton.adapter.outbound.identifier`; 레지스트리 allowed_dependencies=[domain-core, application-core], runtime_memberships=[app-bootstrap, sample-portfolio]; 소비자는 app-bootstrap·sample-portfolio 2곳 | 10 파일 전수이므로 sampling 없음; 저장소 밖 adopter는 덮지 않는다 |
| SRC-085 | reachability / doc drift | `evidence/raw/140-identifier-negative-space-probes.txt` | same revision | 세 production 타입 소비자 계수(`UuidCodec` 0, 나머지 둘은 composition root 배선); `UuidCodec.` 호출은 자기 Spock 스펙 5줄뿐이고 leaf 밖 20+ 파일이 `UUID.fromString`을 직접 호출, D10 대상은 Hibernate `@JdbcTypeCode(SqlTypes.UUID)`가 처리; CLAUDE.md의 build.gradle 선언 서술 3항목 불일치; README의 패키지 루트·Groovy variant·설정 키 3건 오류; ArchUnit `IDENTIFIER_ADAPTER_DOES_NOT_DEPEND_ON_OTHER_ADAPTERS_OR_BOOTSTRAP`는 실재(confirmed)하고 `.claude/hooks/ca_import_gate.py`는 tracked 아님 | `.claude/`는 로컬 설정 영역이라 개발자 머신 존재 여부는 판정 불가 — clone 기준으로만 부재를 기록했다 |
| EVD-070 | 실행 probe | `evidence/raw/140-identifier-negative-space-probes.txt` (EXECUTION PROBE 절) | 2026-08-30 | `normalize("1-1-1-1-1")``"00000001-0001-0001-0001-000000000001"`, `"1-2-3-4-5"``"00000001-0002-0003-0004-000000000005"` (canonical 아닌 입력을 수용해 재작성), `"not-a-uuid"`·무대시 32자·공백 포함은 `IllegalArgumentException`; `normalize(null)`→null / `toUuid(null)`·`fromUuid(null)`→NPE; `newFileId`·`newUploadId` 모두 **version=4**, `UUID.randomUUID()` version=4 | JDK 21의 `UUID.fromString` 동작에 의존하는 결과이며 다른 JDK 버전에서 관대 경로가 달라질 수 있다; 임시 test class는 실행 후 삭제하고 git clean 확인 |
| SRC-086 | module map / denominator | `evidence/raw/141-fileserver-module-inventory.txt`, `src/adapter/outbound/fileserver/**` | same revision | 119 tracked files(main 78 / 12,707 LOC, test 37 / 12,043 LOC, governance 4); 패키지 배치 루트 31 · platform/local 33 · verification 10 · security 2 · audit 2; 별도 source set·test lane 없음; leaf 밖 소비자는 app-bootstrap 하나 | 초기 sizing이며 각 sub-scope의 최종 denominator는 해당 manifest가 확정한다 |
| SRC-087 | config / activation | `evidence/raw/142-fileserver-config-activation-probes.txt` | same revision | 13/13 FULL_READ; R1/R2/플랫폼 세 namespace 분리와 `rejectAmbiguous`의 세 진입점 배치; 적재는 auto-configuration이 아니라 `CaSkeletonApplication`의 명시적 `@ComponentScan`(imports 파일 없음); R1은 `ignoreUnknownFields` 없음·상대 루트 허용·디렉터리 생성, R2는 전부 반대; README가 지목한 selector 기본값이 `application.yml`에 없음 | `.claude`·로컬 설정은 tracked 파일 기준으로만 판단했다 |
| SRC-088 | control plane / codec | `evidence/raw/143-fileserver-control-plane-probes.txt` | same revision | 6/6 FULL_READ(main 2,535 LOC); canonical 왕복 강제(decode 후 재encode 바이트 비교), 인접 전이 행렬과 terminal 종결성, `SecureDirectoryStream` 17회 vs R1 저널 0회, poison 래치의 root 범위와 읽기 허용이 test 이름으로 의도임을 확인; 세 타입 모두 package-private·leaf 밖 참조 0 | 후보 finding 3건을 코드·test로 추적해 결함 아님으로 판정했고 실행 probe는 돌리지 않았다 |
| SRC-089 | publication | `evidence/raw/144-fileserver-publication-probes.txt` | same revision | 26/26 FULL_READ; 19개 production 타입 전부 package-private·leaf 밖 참조 0; `recoverR2`가 상태별로 재개하고 producer를 재생하지 않음; 길이 프레이밍 canonical digest와 route token 충돌 컴파일 검사; R1/R2 엄격도 6축 대조와 두 계층 접점(`decodeStoredOperation`)이 엄격 경로를 쓰는지 확인 | R1/R2 격차는 문서가 선언한 상태이며 결함으로 올리지 않았다 |
| SRC-090 | platform/local IO | `evidence/raw/145-fileserver-local-io-probes.txt` | same revision | 30/30 FULL_READ; `SecureDirectoryWalk`의 서술자 상대 하강과 fallback 부재; `platform/local``Files.*` 호출 전수 조사 → 쓰기 경로에 남은 5곳(`AtomicMoveContentPublisher:53·113·114`, `ContentPublishVerification:53·114`)과 그 유일한 보호가 모듈이 "a precheck could only ever approximate"라 적은 `requireNoSymlinkBetween`; `TransferBufferPool.maxBorrowedBytes()`의 소비자 0 | 발행 rename의 도달성은 스토리지 루트 쓰기 권한에 달려 있고, 그 루트 증명은 app-bootstrap 몫이라 이 leaf 범위에서 확정하지 않았다 |
| SRC-091 | verification / security / audit | `evidence/raw/146-fileserver-verification-security-audit-probes.txt` | same revision | 29/29 FULL_READ; `AdminAuditPort`·`FileserverAuditPort`·`FileAccessPolicy`·`StorageHealthPort`·`OrphanScanPort`·`StorageUsageProbe`·`ReconciliationContentProbe` 구현 8종과 app-bootstrap의 bean 생성 8곳을 확인해 README:105를 반증; 검증 사슬의 fail-closed 합성(timeout/예외 → RETRY, RETRY > ACCEPT); 인가 거부 메시지에 역할 미포함 | bean 생성 지점은 app-bootstrap 소스 기준이며 런타임 컨텍스트로 재확인하지는 않았다 |
| EVD-071 | 실행 probe | `evidence/raw/146-fileserver-verification-security-audit-probes.txt` (EXECUTION PROBE 절) | 2026-08-30 | `inlineSafeProfile=false`에서 `ScriptableContentPolicy` 9종 입력 판정: 평문 `<script>`·`<html>`·선행 공백·대문자·`<svg>`는 QUARANTINE, **UTF-8 BOM + `<html>`·선행 HTML 주석 + `<script>`·NUL + `<html>`는 ACCEPT** | `String.stripLeading()`의 JDK 동작에 의존하는 결과이며, 브라우저별 스니핑 차이는 검증하지 않았다; 임시 test class는 실행 후 삭제하고 git clean 확인 |
| SRC-092 | payload / CSV / testkit | `evidence/raw/147-fileserver-payload-testkit-probes.txt` | same revision | 15/15 FULL_READ; `LocalPersistentPayloadOperations`가 JDK에 서술자 상대 대응물이 없는 세 원시연산(`createLink`·`createDirectory`·force)을 javadoc에 선언하고 identity 검사로 감싼 것을 호출 전수로 확인; CSV 인코더의 세 상한과 수식 정책 3종; `CrashRecoveryMatrixTest``@EnumSource(CrashPoint.class)`로 전 크래시 지점을 순회하고 두 발행 전략이 같은 `ContentStoreContract`를 상속 | testkit의 NFS·PVC fixture는 해당 환경이 없어 실행하지 않았다 |
| SRC-093 | module map / denominator | `evidence/raw/149-objectstorage-module-inventory.txt`, `src/adapter/outbound/objectstorage/**` | same revision | 206 tracked files(main 147 / 14,336 LOC, test 48 + resource 1 / 6,753 LOC, qualification source set 3종 6 files / 546 LOC, governance 4); 패키지 배치 `s3` 26 · `control` 24 · `kernel` 23 · `config` 19 · `direct` 13 · `readiness` 8 · `maintenance` 8 · `codec` 7 · `filesystem` 6 · `multipart` 5 · `provider` 4 · 루트 4; AWS SDK v2 BOM을 모듈 범위로 import; 레지스트리 allowed_dependencies=[application-core, shared-contract], runtime_memberships=[sample-portfolio] | 초기 sizing이며 각 sub-scope의 최종 denominator는 해당 manifest가 확정한다 |
| SRC-094 | governance / config / routing | `evidence/raw/150-objectstorage-config-activation-probes.txt` | same revision | 28/28 FULL_READ; `app.object-storage`는 기본 비활성이고 legacy alias와 혼용 시 예외; `ObjectStorageProviderContribution`이 describe(부작용 없음)와 create(부분 할당 정리 책임)를 분리; `filesystem-local-dev`가 production 프로파일에서 거부되나 판정이 `prod`/`production` 두 리터럴 소문자 비교; `RoutingObjectReadAdapter`의 무방비 `split("\\.",-1)[1]``ObjectReference` 생성자 검증이 막아 결함 아님 | `.claude`·로컬 설정은 tracked 파일 기준으로만 판단했다 |
| SRC-095 | control plane / canonical JSON | `evidence/raw/151-objectstorage-control-probes.txt` | same revision | 25/25 FULL_READ(main 2,470 LOC); canonical 강제가 reader·writer·봉투 세 겹; 레코드 불변식이 값이 아니라 상태-증거 관계를 검증; 열거 API 부재로 키 공간 스캔이 표현 불가; 관용 UTF-8 디코딩 후보를 printable ASCII 검사로 추적해 결함 아님으로 판정 | zero-finding 결과이며 실행 probe는 돌리지 않았다 |
| SRC-096 | kernel / codec | `evidence/raw/152-objectstorage-kernel-codec-probes.txt` | same revision | 39/39 FULL_READ; 닫힌 상태 전이 행렬과 terminal 종결성, epoch fencing, pending effect / 응답 유실 화해; `markEffectSent`·`markResponseLost``current.updatedAt()`을 그대로 넘겨 의도 시각과 유실 시각이 durable 레코드에 남지 않음 | 정적으로 결정 가능한 지점이라 실행 probe 불필요 |
| SRC-097 | s3 provider | `evidence/raw/153-objectstorage-s3-probes.txt` | same revision | 40/40 FULL_READ(main 3,581 LOC); AWS SDK 참조가 `s3/**` 16 + legacy 3에 갇히고 leaf 밖 production 유출 0(밖의 hit는 ArchUnit 금지 타입 카탈로그와 빌드 파일뿐); `S3ClientPolicy`가 재시도 최악 예산 ≤ 부모 호출 예산을 강제하고 평문 AWS 엔드포인트를 거부하며 자격증명을 `[REDACTED]`로; `S3ProviderBinding`이 AWS/MinIO에 반대 방향 신원 규칙을 강제하고 `autoCreateBucket`·`publicAcl`을 금지; `S3ProviderErrorMapper`가 mutation 불확실성을 `INDETERMINATE, authoritative=false`로 보존 | zero-finding 결과; 실제 AWS/MinIO 호출은 하지 않았고 정책·매핑의 정적 판정만 수행했다 |
| SRC-098 | direct transfer / multipart | `evidence/raw/154-objectstorage-direct-multipart-probes.txt` | same revision | 25/25 FULL_READ; `requirePartSize`의 세 호출 지점 중 `DirectMultipartCoordinator:163``finalPart=false` 하드코딩이고 `PartUploadGrantRequest`에 마지막 part 표시 없음; `validateSignedGrant`가 upload 경로 1곳에만 있고 `expectedExpiry`는 미검사, `planningEndpoint()`는 정의상 항상 통과; coordinator·policy의 패키지 밖 참조 0이고 README가 "no direct-grant port is registered"로 선언하나 AWS binding은 `DIRECT_*` capability 주장을 통과시켜 presigner를 할당(MinIO는 거부) | 미배선 상태라 실행 probe 불가; 세 finding 모두 호출 인자·호출 부재·조립 경로로 정적 확정했다 |
| SRC-099 | filesystem / maintenance / readiness / provider / 루트 | `evidence/raw/155-objectstorage-platform-readiness-probes.txt` | same revision | 43/43 FULL_READ(main 30 / 2,420 LOC); readiness 레지스트리 forward reference 해소 — `docs/registries/object-storage-readiness.yaml`는 저장소 루트에 실재하고 build.gradle이 시스템 프로퍼티로 전달, leaf test가 9장 카드 집합·R1 두 장·R0 여섯 장을 강제; `legacy-adoption.enabled=true, mode=APPLY`는 설정으로 켜지는데 `Ed25519LegacyAdoptionApprovalVerifier` 생성 지점이 저장소 전체 0이고 승인자 키 설정 항목도 없음; `ClaimResult`가 발행을 막지 않음; `filesystem-local-dev` capability 표 2벌; legacy 루트에 production 프로파일 검사 없음 | 승인 검증기의 부재는 tracked 소스 기준이며, fork가 자체 bean을 공급하는 경우는 관측 범위 밖이다 |
| SRC-100 | qualification lanes | `evidence/raw/156-objectstorage-qualification-lanes-probes.txt` | same revision | 6/6 FULL_READ; 세 lane 모두 strict·non-skipping·`requiredClasses` 고정; 여섯 파일 중 provider를 실제로 호출하는 것은 `MinioManagedObjectContractTest`(digest 고정 MinIO에서 `If-None-Match: *` PUT과 CompleteMultipartUpload가 기존 객체를 덮고 stale `If-Match`만 412)와 `MinioManagedObjectFaultTest`(Toxiproxy 절단 → 5초 이내 유계 실패와 복구) 둘뿐; AWS lane 2종은 환경변수만 검사; provider 신원 문자열과 이미지 digest가 enum·version map·evidence JSON 세 곳에 독립 기재되고 교차 검사 없음 | lane 실행에는 Docker와 보호된 AWS sandbox 권한이 필요해 이 분석에서 실행하지 않았고, lane이 주장하는 내용과 그 소비처만 정적으로 추적했다 |
| EVD-072 | suite 검증 | `evidence/raw/157-objectstorage-suite-verification.txt` | 2026-08-30 | `:adapter:outbound:objectstorage:test` → classes=47 tests=140 failures=0 errors=0 **skipped=0**; `git status --short` 변경 0 | qualification source set 3종은 `:test`에 포함되지 않으며 Docker·AWS sandbox 권한이 필요해 실행하지 않았다 |
| SRC-101 | module map / denominator | `evidence/raw/158-cache-redis-module-inventory.txt`, `src/adapter/outbound/cache-redis/**` | same revision | 390 tracked files(main 316 / Java 314 · 32,082 LOC + resource 2, test 70 / Java 69 · 15,244 LOC + golden 1, governance 4); 자체 Redis SDK를 품은 leaf로 설계 문서의 다중 모듈 배치를 패키지 경계로 대체하고 `RedisSdkModuleBoundaryTest`가 강제; build.gradle이 spring-data-redis·micrometer 부재를 근거와 함께 선언하고 `redisTopologyTest` lane 4종에 mode allowlist·필수 클래스·최소 test 수·skip 0 게이트를 건다 | 초기 sizing이며 각 sub-scope의 최종 denominator는 해당 manifest가 확정한다 |
| SRC-102 | governance / config / 조립 | `evidence/raw/159-cache-redis-config-activation-probes.txt` | same revision | 26/26 FULL_READ; `app.redis.enabled` 하나가 전체 스위치이고 `RedisSdkSettings``@ConfigurationPropertiesScan` 밖이라 "contributes nothing"이 문자 그대로 성립(test 4종); auto-configuration이 @Bean 7개(settings·validation·credentials·**client**·**runtime owner**·**redisOptional**·**redisRequired**)를 만들어 README의 "조립되지 않는다" 서술 중 셋을 반증; `RedisStartupProbe`/`RedisCapabilityProbe`의 production 호출자 0; raw allowlist 기본 리소스 부재는 startup 실패로 닫혀 있어 결함 아님 | 승인자 키·capability 설정은 tracked 소스 기준이며 fork의 자체 bean 공급은 관측 범위 밖 |
| SRC-103 | 타입 있는 명령 표면 | `evidence/raw/160-cache-redis-api-surface-probes.txt` | same revision | 83/83 FULL_READ; `Expiration`이 sealed이고 `Persistent`가 permit을 요구해 TTL 없는 쓰기가 표현 불가; permit/budget 요구를 4종으로 분류; "설계상 부재" 6건(`KEYS`·`SETNX`/`SETEX`/`PSETEX`·`ZREVRANGE`·`RPOPLPUSH`/`BRPOPLPUSH`·`GEORADIUS`·`members()`)을 API·Lettuce 구현·명령 정책 yml 세 계층에서 대조(`KEYS`는 R4 BLOCKED); `ApiParityTest`가 sync/reactive 대칭을 반사로 강제하고 검사기 자신의 메타 test 보유; `RedisOperations`·`ReactiveRedisOperations` 구현 0 | 개별 표면 43종은 전부 구현돼 있으며 facade만 없다 |
| SRC-104 | 키 · 실패 · 명령 기술 · reactive | `evidence/raw/161-cache-redis-key-error-command-probes.txt` | same revision | 64/64 FULL_READ; 렌더된 키를 받는 API 부재를 sealed 계층과 renderer 단일 지점으로 확인; `RedisFailureMetadata`의 "모호 실행은 retryable 불가" 불변식과 `storedDataCorruption` 팩토리의 분리(실호출 2곳); `RedisCommandDescriptor`의 교차 필드 불변식 4종; `requireIdentifier`의 메일·전화 분기가 선행 문자 클래스에 가려 도달 불가이고 test는 타입만 검사; reactive `getRange` 누락 의심을 직접 diff로 오탐 판정 | 예외의 `transient metadata`는 직렬화 왕복 시 null이며 문서에 없다 |
| SRC-105 | gateway · request builder | `evidence/raw/162-cache-redis-gateway-probes.txt` | same revision | 95/95 FULL_READ(main 10,718 LOC); `RedisCommandGateway`가 114개 명령별 메서드로만 이루어지고 명령 이름을 받는 메서드 0; 11개 계열 전부 sync/reactive가 같은 `*OperationRequests`를 생성; `RedisOperationContext`가 R1 permit 검증·scan overshoot 허용(+512)·BLMOVE 이중 permit 처리를 한 곳에 모음; 응답 예산 강제 12곳; 구독 경로만 guard를 지나지 않고 그 대체 검사(네임스페이스·패턴 permit)가 실재; permit 정책 이름이 Java 18 + YAML 18 + 별도 상수 1로 흩어짐 | in-memory double은 `implements`로 114 메서드가 강제되므로 누락 의심은 오탐 |
| SRC-106 | guard · 연결 · 코덱 · 관측 | `evidence/raw/163-cache-redis-guard-connection-codec-probes.txt` | same revision | 44/44 FULL_READ; guard의 고정 순서 11단계와 두 건의 수정 이력(죽은 `validateReply` 제거, 발화 불가였던 다중 키 절 분리); 정책 문서를 일반 YAML 엔진으로 읽지 않는 이유와 그 좁은 파서; 레인이 계정을 함께 유도(`SCRIPT`→ADVANCED); `RedisRuntimeOwner`의 OPEN→DRAINING→CLOSED와 포화 시 거부; 두 실행자가 같은 협력자 4종; **`RedisCommandMetadataDiff`("The build gate")의 main 참조 0 · lane 참조 0 · Gradle 태스크 0**; 정책 문서 필드 표 11 vs loader allowlist 12 | drift gate의 비교 로직과 test 6종은 완성돼 있고 없는 것은 실제 서버 메타데이터를 넣는 연결이다 |
| SRC-107 | 스크립트 · 트랜잭션 · 확장 · raw · 클러스터 | `evidence/raw/164-cache-redis-programmability-extensions-probes.txt` | same revision | 54/54 FULL_READ; raw gateway가 카탈로그 `RAW_ONLY` 분류와 배포 승인 두 문을 모두 요구하고 토큰이 발급 레지스트리 인스턴스까지 검증; `RawMovableKeys``SORT`/`SORT_RO` 한 형태만 파싱하고 `BY`/`GET`은 패턴이라 의도적으로 거부(test 8종); 스크립트 등록이 배포 단계이고 README의 EVALSHA→NOSCRIPT→SCRIPT LOAD 사슬이 `forget(...)` 호출로 실재; 그러나 NOSCRIPT 판정이 5벌이고 4벌이 레지스트리를 우회; 슬롯 검사 2곳은 범위가 달라 중복 아님 | 진입 타입 5종(raw gateway·transaction runner·admin·cluster observer/cursor)의 production 참조 0 |
| SRC-108 | 의미 포트 어댑터 | `evidence/raw/165-cache-redis-semantic-adapters-probes.txt` | same revision | 24/24 FULL_READ; `CacheRegionPort`·`IdempotencyStorePortV2`·`DistributedLeasePort`·`EdgeRateLimitPort`·`ConnectionRegistryPort`·`EphemeralFanoutPort` **6종 3,295 LOC 구현 확인**(전용 test 5 + `LiveRedisSemanticPortsTest`)으로 README의 "그 코드는 이 leaf에 없다"를 반증; 포트별 실패 정책 대비(cache만 degrade, rate limit은 fail-closed, idempotency는 INDETERMINATE); **다섯 어댑터가 guard·executor·타입 API 참조 0이고 `lease.gateway()`를 직접 호출(30곳)**; `CapabilityKeyspace``requireRenderedSize`를 적용하지 않는 두 번째 키 렌더 경로 | 현재 미배선이므로 즉각 노출은 없고, 키는 같은 `RedisNamespace`에서 조립되므로 네임스페이스 봉쇄만은 구성으로 유지된다 |
| EVD-073 | suite 검증 | `evidence/raw/166-cache-redis-suite-verification.txt` | 2026-08-30 | `:adapter:outbound:cache-redis:test` → classes=52 tests=435 failures=0 errors=0 **skipped=0**; `git status --short` 변경 0 | `redisTopologyTest` lane 4종은 `excludeTags`로 제외되며 실제 서버와 `-Predis.topology.*`를 요구해 실행하지 않았다 |
| SRC-109 | module map / denominator | `evidence/raw/167-httpclient-module-inventory.txt`, `src/adapter/outbound/httpclient/**` | same revision | 370 tracked files(main 260 / 15,004 LOC, test 62 / 6,049, testkit source set 35 / 2,754, httpClientPerformanceTest 7 / 495, jmh 2 / 130, governance 4); 설계의 19-모듈 배치를 패키지 경계로 대체하고 `HttpClientModuleBoundaryTest`가 강제; HTTP/3가 `compileOnly`인 이유·Jackson 3가 필수인 이유·testkit이 별도 source set인 이유·lane 둘이 `failOnNoDiscoveredTests`를 잃었던 기록이 build.gradle 주석에 있음; `check`에 hermetic lane 4종이 붙음 | 초기 sizing이며 각 sub-scope의 최종 denominator는 해당 manifest가 확정한다 |
| SRC-110 | profile / startup 검증 | `evidence/raw/168-httpclient-profile-probes.txt` | same revision | 35/35 FULL_READ; `ClientProfileValidator`**34종 위반 코드**를 결정적 정렬로 내고 각 코드가 막는 다운그레이드를 주석으로 적음(바인딩되지만 전송에 닿지 않는 설정 3종을 무시가 아니라 **거부**); app-bootstrap `HttpClientStartupValidator:37`이 실제 배선; `ClientRuntimeRegistry.close()``throw firstFailure`를 스케줄러 종료보다 먼저 실행; `POOL_ROUTE_EXCEEDS_TOTAL``PoolSettings` 생성자에 가려 도달 불가; 34종 중 test가 이름으로 잡는 것은 12종 | 위반 코드별 test 참조 계수는 `test`/`testkit` source set 전체 기준 |
| SRC-111 | 공개 API 어휘 | `evidence/raw/169-httpclient-api-probes.txt` | same revision | 55/55 FULL_READ; 증거 3축(`ExecutionEvidence`·`AttemptStage.provesNotSent`·`BodyReplayability.weakest`)과 `OperationIdempotency`가 D-09를 구성; `HttpFailureMetadata`가 제외 목록을 열거하고 `HttpOperation`·`ObjectBody`·`IdempotencyKey`가 각각 과거 유출을 근거로 `toString`을 재정의; `TRACE` 부재를 test가 반사로 확인; `ObjectBody.deeplyImmutable``instanceof Number``AtomicInteger`류 가변 타입을 통과시킴 | `api/body` 7종 중 값을 담는 둘만 toString 재정의가 필요함을 전수 확인 |
| SRC-112 | 재시도 자격 · 가드 파이프라인 | `evidence/raw/170-httpclient-resilience-probes.txt` | same revision | 47/47 FULL_READ(test 47 메서드); 결정표가 절대 차단 6 → 영구 → 증거 → 상태/실패 순으로 단조; 408/425/429가 멱등성 검사를 건너뛰던 수정 이력; **`AttemptResiliencePipeline`이 회로 permission을 얻은 뒤 rate/bulkhead 거부 경로에서 반환하지 않음**(`releasePermission` 저장소 전체 매치 0, bulkhead 경로는 rate 토큰만 반환); `PARTIAL_RESPONSE` 분기 도달 불가 의심을 전송 분류기 4종의 생산 지점으로 오탐 판정 | Resilience4j HALF_OPEN 시험 슬롯 소진은 라이브러리 의미론에 근거한 추론이며 실행 재현은 하지 않았다 |
| SRC-113 | 게이트웨이 · 응답 경계 | `evidence/raw/171-httpclient-gateway-probes.txt` | same revision | 46/46 FULL_READ; 와이어/디코드 두 예산과 읽는 도중 강제; `RemoteProblemDecoder`가 원격 `status`를 폐기하고 와이어 상태를 신뢰; `BlockingRedirectCoordinator`가 hop마다 allowlist 재적용·cross-origin 자격증명 제거·303 본문 폐기; `BoundedDataBufferFlux``doOnCancel`·`onErrorResume`가 no-op; 리다이렉트 hop 상한은 `RedirectEvaluator:16`이 강제(오탐 판정) | 버퍼 누수를 주장하지 않았다 — no-op 연산자와 javadoc의 불일치만 기록 |
| SRC-114 | 보안 · 자격증명 | `evidence/raw/172-httpclient-security-auth-probes.txt` | same revision | 46/46 FULL_READ; 절대 URI를 정화가 아니라 거부; 멱등성 키가 실제로 헤더로 나가지 않던 수정("A duplicated payment is the shape of that bug"); `HeaderPolicy`의 소유 헤더 9종과 CR/LF 거부; `SensitiveHeaderStripper`의 "adds rather than replaces" 수정; `auth` record 5종 중 값을 담는 셋 모두 redacted toString; zero-finding | 가짜 메타데이터 편의 생성자는 production 호출자 0으로 확인 |
| SRC-115 | 동적 대상 · 관측 · 서비스 | `evidence/raw/173-httpclient-service-dynamic-probes.txt` | same revision | 56/56 FULL_READ; SSRF 사슬(정규화 → 전체 응답 검증 → thread-local 핀 → 전송 resolver 주입)을 호출 지점으로 전수 추적, app-bootstrap `HttpClientTransportAutoConfiguration:81``CallScopedDnsPin::addressesFor`를 주입; `HttpClientTagPolicy`가 모르는 태그를 거부하고 쿼리 값은 통째로 폐기; 계약 lane의 메타 test 3종; `ValidatedDnsResolver.approved` 무경계 의심을 `finally``forget`과 production 호출자 0으로 오탐 판정 | zero-finding |
| SRC-116 | 전송 6종 · testkit / perf / jmh | `evidence/raw/174-httpclient-transport-testkit-probes.txt` | same revision | 85/85 FULL_READ; `TransportCapabilityValidator`가 프로파일 요구와 전송 선언을 대조해 startup 거부; **`validatedDnsPinning` 검사가 블로킹 오버로드에만 있고 리액티브에는 없음** — 주석이 "the two were being conflated"라고 지적한 상태가 한쪽에 잔존(현재 두 리액티브 전송은 두 플래그가 같아 노출 없음); testkit 계약 클래스 6종을 세 lane이 공유; 성능 lane 7종은 풀·재시도·회전·토큰경합·본문·H2를 재고 본문 재생 가능성 판정 비용은 재지 않음 | HTTP/3는 `compileOnly``Http3CapabilityReport`가 클래스 부재 시 startup에서 거부 |
| EVD-074 | suite 검증 + 실패 진단 | `evidence/raw/175-httpclient-suite-verification.txt` | 2026-08-30 | `:check``src/gradle/archive-hygiene.gradle` 게이트가 `build/libs`의 이전 리비전 JAR 2개를 발견해 실패(소스 무관, remedy 태스크 `cleanStaleTraceableJars` 존재, **이 분석은 삭제하지 않음**); lane 5종 개별 실행 → `test` 283/3 failed, 나머지 4 lane 42 tests 0 failed, skipped 0; 실패 3건은 `MutualTlsHandshakeContractTest``expected: TLS_HANDSHAKE but was: CONNECT``ApacheFailureClassifier`가 원인 사슬을 바깥부터 훑는데 CONNECT 분기가 TLS 분기보다 앞서 `HttpHostConnectException`이 안쪽 `SSLHandshakeException`을 가림; `git status --short` 변경 0 | hermetic test이고 의존성이 잠겨 있어 결정적으로 재현된다 |
| SRC-117 | module map / denominator | `evidence/raw/176-outbound-messaging-module-inventory.txt` | same revision | 69 tracked files(main 46 / Java 34 · 4,246 LOC + resource 12, test 19 / Java 16 · 3,670 LOC + resource 3, governance 4); build.gradle이 YAML·Jackson 2를 전 configuration에서 제외하고 `verifyJsonSchemaRuntimeGraph``check`에 붙임; qualification lane 2종이 필수 클래스 목록과 함께 등록되고 루트 `:prepareMessagingContractEvidence`에 의존 | 초기 sizing |
| SRC-118 | 활성화 · 조립 | `evidence/raw/177-outbound-messaging-activation-probes.txt` | same revision | 14/14 FULL_READ; `app.messaging.enabled`(스위치)와 `app.messaging.broker`(선택자)의 분리와 그 이유; `MessagingOffAutoConfigurationImportFilter``spring.factories`에 실제 등록되어 Boot의 Kafka/AMQP 자동설정 5종을 차단; **실행 probe: `verifyJsonSchemaRuntimeGraph` FAILED — 요구 좌표 `tools.jackson.core:jackson-core:3.0.2` vs 잠긴 `3.1.5`**; `CompiledMessagingDescriptor`의 leaf-main·app-bootstrap 참조 0이며 계약·목적지·봉투·스키마 4패키지를 leaf 밖에서 참조하는 파일 0 | 컴파일된 절반의 목적(증거 산출)은 build.gradle의 lane 구성에서 추론했고 문서에는 없다 |
| SRC-119 | 닫힌 JSON Schema 레지스트리 · 봉투 | `evidence/raw/178-outbound-messaging-envelope-probes.txt` | same revision | 21/21 FULL_READ; 어휘 allowlist 8종·닫힌 키워드 부분집합 5종(`$anchor`·`$dynamic*`·`$recursive*`)·참조 사전 검사·핀 고정 메타스키마 9종; **실행 probe: `authority.sha256`의 9개 해시가 동봉 파일의 실제 SHA-256과 전부 일치**; 봉투 작성이 원시 JSON 파서/생성기 API 없이 스냅샷 바이트를 삽입하고 가변 접근자를 한 번만 호출; 적대적 test 29 메서드가 파서·수·컬렉션·해시 경계를 이름으로 고정 | zero-finding |
| SRC-120 | 계약 컴파일 · 목적지 · 파티션 키 | `evidence/raw/179-outbound-messaging-contract-destination-probes.txt` | same revision | 13/13 FULL_READ; 열린 타입(raw·wildcard·Map·JSON 트리·인터페이스·제네릭 record 그래프)을 페이로드로 거부하고 기여 접근자를 정확히 한 번만 호출; 도메인 분리 상수 7종이 전부 버전 붙은 형태이고 4바이트 길이 프레이밍을 공유; 카탈로그 다이제스트가 입력 순서 독립; `PartitionKeyV1`이 교차 언어 벡터 진입점을 제공하고 골든 벡터 2종(비ASCII UTF-8 바이트 길이 포함) 보유 | zero-finding |
| EVD-075 | suite 검증 | `evidence/raw/180-outbound-messaging-suite-verification.txt` | 2026-08-30 | `:adapter:outbound:messaging:test` → classes=17 tests=92 failures=0 errors=0 **skipped=0**; `:check``verifyJsonSchemaRuntimeGraph`에서 실패(게이트 자신의 버전 하드코딩); `git status --short` 변경 0 | qualification lane 2종은 루트 증거 파이프라인에 의존해 실행하지 않았다 |
| SRC-121 | 바인딩 컴파일 · 템플릿 카탈로그 | `evidence/raw/183-notification-catalog-dispatch-probes.txt` | same revision | 23/23 FULL_READ; digest 헬퍼가 문자열을 4바이트 길이 프레이밍으로 먹여 인접 필드 충돌을 구조적으로 배제; `LocalEmailRenderer`의 컨텍스트 인지 이스케이프 사슬(태그 27종 허용목록 → 토큰 문법이 컨텍스트를 요구 → **삽입 위치 검증** → 치환 시점 컨텍스트별 이스케이프 → `quoteReplacement` → 미해결 `{{` 거부)을 전수 확인; 템플릿 자산은 manifest 체크섬 + 계획에 얼어붙은 체크섬·렌더러 리비전 이중 대조; **`validateRouteShape``SINGLE` 전용 가드(`:141`)가 `switch`(`:159`)보다 앞서 `FAN_OUT_ALL`·`ORDERED_FALLBACK`·`default`와 순환 탐지기 전체가 도달 불가**이고 `legacyReceiptUnsafeFallbackBoundsAndCyclesAreRejected``hasMessageContaining("strategy")`로 다른 가드에 걸려 통과 | 순환 탐지기는 정적으로 도달 불가를 증명했고 실행으로 반증하지는 않았다 |
| SRC-122 | 스케줄러 · 런타임 세대 · 시도 permit | `evidence/raw/183-notification-catalog-dispatch-probes.txt` | same revision | 30/30 FULL_READ; **실행 probe: 배경 작업자 3종(`LeaseRecoveryService`·`ProviderEventReplayWorker`·`ReconciliationJobWorker`)이 app-bootstrap `NotificationPlatformWorkerConfig`에 빈으로 등록되고 `NotificationBackgroundWorkers.start()`가 각각 `scheduleWithFixedDelay` — 배선 확인됨**(cache-redis `RedisStartupProbe` 호출자 0과 대조); 상태 전이 7종을 형제로 비교해 `markDraining`/`markDisabled``current`를 받고 쓰지 않음을 확인; **`AUTHENTICATION_FAILED → markDraining() → resumeHealthy()``RegistryProviderRuntimeControl:30-39`를 통해 관리자에게 노출되어 javadoc이 선언한 거부를 우회하고 원인 코드를 파괴**; `ProviderRuntimeStateTest:125-140`이 세 전이를 각각 새 객체에서만 확인 | 우회는 정적 증명(무조건 덮어쓰기 3줄)이며 실행 재현은 하지 않았다 |
| SRC-123 | 렌더링 이스케이프 · 저장 시 암호화 | `evidence/raw/184-notification-template-security-probes.txt` | same revision | 32/32 FULL_READ; `SecretPurpose` 8종이 소유자 1:1이고 `NotificationSecretRequirements`가 전부 열거; `AesGcmContactPointProtector`가 두 키를 요구하고 keyId·자료 양쪽으로 동일성 거부, AAD에 접촉점 종류 결속, 키 256비트 강제; **`.auditRequired()` 0건 · `.purposeCode()` 0건 — "Every reveal is auditable"를 선언한 `AccessContext`의 필드를 읽는 코드가 저장소에 없고 `reveal`은 null 검사만 함**(감사 싱크 `LoggingNotificationAudit`은 존재하며 `ProviderRuntimeRotator`가 사용); **Thymeleaf `process(` 2곳 중 `catch``:92` 하나 — 프로덕션이 타는 mode-aware 오버로드(`:80`)는 무방비**이고 `CanonicalNotificationRenderer:125,133`이 모드 있는 쪽만 호출 | 메시지 유출의 실제 문자열은 Thymeleaf 구현에 달려 있어 실행으로 확인하지 않았다 |
| SRC-124 | provider 포트 · SPI 라우팅 · 관측 | `evidence/raw/185-notification-provider-core-probes.txt` | same revision | 38/38 FULL_READ(main 29 + test 9, probe가 카운트 확인); **`Retry-After` 힌트가 `NotificationDispatchService:381``RetryBackoff:44-45`로 도달하고 계산값보다 길 때만 채택된 뒤 `max`로 상한 — javadoc 주장과 일치, 회로 닫힘**; `RoutingNotifier`가 채널 내 `providerId` 중복과 미등록 라우트를 생성자에서 거부하고 런타임 미바인딩은 `AdapterDisabledException`; 첨부 무결성이 `AttachmentIntegrityGuard.resolve` 안에서 크기·다이제스트를 `MessageDigest.isEqual`로 대조; `NotificationHealthReporter`가 unhealthy로 보는 4조건에 `DRAINING`이 없어 SRC-122의 우회가 헬스 신호도 함께 끔; 음수 `Retry-After``ProviderFailure` 생성자에서 `IllegalArgumentException` | 음수 헤더는 RFC 비준수 provider를 전제하며 실행 재현하지 않았다 |
| SRC-125 | provider 구현 8종 · SigV4 · SNS · RFC 8291 | `evidence/raw/186-notification-provider-impl-probes.txt` | same revision | 76/76 FULL_READ(main 60 + test 16, probe가 카운트 확인); **`requireExternallyRoutable`의 프로덕션 호출처는 SES·webhook 둘뿐이고 가드 javadoc이 지목한 "Web Push endpoints and webhook targets"와 다름 — `WebPushSubscriptionValue:50-57`이 약한 스킴 검사의 private 사본을 들고 있어 grep으로도 드러나지 않으며 `EndpointGuardCallSiteTest`에 WebPush 언급 0**; **`boundedBody``BodySubscribers.ofByteArray()`를 upstream으로 써서 전부 읽은 뒤 `mapping`으로 자름 — 주석의 "not ofByteArray()"와 반대**; SigV4가 `getHost()`(포트 없음)를 서명하고 JDK는 포트 포함 `Host`를 보냄; `AwsSignatureV4Signer:117-119`가 비밀을 `String`으로 승격(leaf 내 유일); SNS `SignatureVersion` 1(SHA-1)을 발신자가 선택 가능하고 v2 강제 설정 없음 | Web Push SSRF는 이 템플릿에 인바운드 등록 경로가 동봉되지 않아 현 상태로는 미도달 — 포크가 붙이는 순간 통과된 상태가 된다 |
| SRC-126 | SPI 기여 2종 · 계약 testkit | `evidence/raw/187-notification-spi-testkit-probes.txt` | same revision | 19/19 FULL_READ(main 6 + test 9 + resources 4); `ProviderFaultHarness`가 목이 아닌 실제 JDK HTTP 서버 소켓을 띄워 "본문 기록 후 연결 절단"을 재현; `PiiLeakScanner`가 패턴이 아니라 정확한 픽스처 값을 탐색; 성능 lane이 처리량이 아니라 규모 무관 성질만 게이트; **`ProviderResults.fromTransport` 호출 어댑터 6종에 FCM이 없고 `FcmBatchCoordinator``gateway.sendBatch`를 try 없이 호출 — "커밋 후 응답 손실 = ambiguous" 규칙 밖의 유일한 provider이며 배치라 한 번의 손실이 배치 크기만큼 영향**; `extends ProviderAdapterContract` 3/8, `ContractAdapters` 등록 5/8, FCM 테스트에 `AMBIGUOUS` 0건 — 두 계약 집합이 모두 비껴간 provider가 계약을 만족하지 않는 provider | FCM 전송 실패의 실제 예외 타입은 포크가 넣는 `FcmGateway` 구현에 달려 있다 |
| EVD-076 | suite 검증 | `evidence/raw/187-notification-spi-testkit-probes.txt` | 2026-08-30 | `:adapter:outbound:notification:test``BUILD SUCCESSFUL`, `GRADLE_EXIT=0`; 이 모듈의 발견 7건(P2)은 모두 테스트가 통과하는 상태에서 나왔다 — 두 건(SRC-121·SRC-122)은 통과하는 테스트가 다른 이유로 통과하거나 합성을 확인하지 않은 경우 | `:check`는 실행하지 않았다(httpclient에서 확인된 `archive-hygiene` 스테일 JAR 게이트가 소스와 무관하게 실패하며, 이 분석은 build 산출물을 삭제하지 않는다) |
| SRC-127 | module map / denominator / 소스셋 | `evidence/raw/188-inbound-web-module-inventory.txt` | same revision | 638 tracked files이 **여섯 소스셋**으로 갈림(main 400 · test 150 · testkit 54 · webfluxContractTest 16 · jettyCompatTest 9 · nginxProxyTest 5 · governance 4); main Java 27,473 LOC · test Java 18,319 LOC · main 패키지 74개; build.gradle이 각 소스셋 분리의 근거를 "그렇게 하지 않으면 레인이 무엇을 인증하게 되는가"로 적음(Jetty 레인이 Tomcat 위에서 돌 위험 · 리액티브 게이트가 서블릿 스택을 인증할 위험 · Docker 없는 `check``@Disabled`로 귀결될 위험) | 초기 sizing; 12개 sub-scope 분할은 이 트리에서 기계 계산 |
| SRC-128 | 패키지 도달성 지도 | `evidence/raw/192-inbound-web-package-reachability.txt` | same revision | main 74개 패키지 각각에 대해 (a) 다른 web main 패키지가 import하는 수 `in`, (b) app-bootstrap/sample-portfolio가 import하는 파일 수 `ext`를 기계 산출. `security` `in=0 ext=0`(11파일) · `cache` `in=0 ext=0`(4) · `advanced/*` 대부분 `in=0 ext=0` · `fileserver.*``ext>0`가 다수. 이 지도가 SS3~SS11의 도달성 판정 기준선 | import 기반이므로 리플렉션·컴포넌트 스캔 경로는 별도 확인 필요(각 sub-scope에서 수행) |
| SRC-129 | 거버넌스 · 모듈 경계 강제 | `evidence/raw/189-inbound-web-governance-probes.txt` | same revision | 51/51 FULL_READ; **다섯 커스텀 레인의 Gradle 참조 0, CI 워크플로 다섯 파일이 전부 호출 — 회로는 YAML에서 닫힘**; `WebStableModule`(539줄 enum)이 모듈 id·패키지·순도·허용 edge를 선언하고 `WebModuleBoundaryTest`가 실제 트리를 스캔해 양방향 대조(긍정 5규칙 + **부정 픽스처 4개** + 빈 스캔 거부); 프레임워크 탐지 정규식에 Jackson 2·3 병기("a hole in exactly the check that is supposed to have none"); `CorsSettings``contains("*")``setAllowedOrigins` 소비처와 정확히 짝 | 레인 실행은 하지 않음 |
| SRC-130 | 에러 계약 이중화 | `evidence/raw/190-inbound-web-error-probes.txt` | same revision | 33/33 FULL_READ; **두 `@RestControllerAdvice`가 같은 컨텍스트에 등록되어 다섯 프레임워크 예외에서 `problem+json`이, 나머지 22종에서 `Envelope`이 나간다**(`WebMvcProblemExceptionHandler` `@Order(HIGHEST_PRECEDENCE+10)` vs 무순서 `GlobalExceptionHandler`); README:168이 "D5: RFC 7807 ProblemDetail 표현은 거부"를 선언하고 `problem+json`/`RFC 9457`/`ProblemCode` 언급 0; leaf의 어떤 테스트도 두 advice 를 함께 세우지 않으며 `NoResourceFoundErrorHandlingTest`는 이기는 쪽을 `@Import`에서 빼고 지는 쪽을 단언; `WebProblemSanitizer.alreadySafe` 호출자 0이고 내부 삼항도 도달 불가 | 두 advice 공존 시의 실제 응답은 정적 추론(순서 규칙)이며 실행 재현하지 않음 |
| SRC-131 | 신원 · 요청 컨텍스트 배선 | `evidence/raw/191-inbound-web-security-probes.txt` | same revision | 44/44 FULL_READ; **`WebMvcRequestContextHolder.store()` 호출자 저장소 전체 0**이고 자동설정이 등록한 argument resolver는 `require()`로 항상 throw; `new WebRequestContext(` main 유일 지점이 `WebFluxRequestContextFilter:81`이며 `ActorContext.anonymous()`·`TenantContext.none()`·`Locale.ENGLISH`·`ApiMajorVersion(1)` 넷을 상수로 채움; `security` 패키지 11파일이 서로만 참조(`WebSecurityContextBridge` main_refs=0, `AuthenticationView` 생성은 테스트뿐), 교차 테넌트 가드 `rejectTenantInput`이 그 섬 안에만 존재; `publicPaths` permitAll이 `RestrictedPathRule`보다 먼저 등록됨 | 관리자 2단계 우회(§12.4의 auth-mode 철자)는 Spring `@ConditionalOnProperty``equalsIgnoreCase` 동작에 대한 정적 추론 |
| SRC-132 | 용량 보호 계층의 등록 지점 | `evidence/raw/193-inbound-web-capacity-probes.txt` | same revision | 50/50 FULL_READ; **`WebMvcBudgetFilter`·`WebFluxBudgetFilter`·`WebMvcThrottleFilter`·`WebFluxThrottleFilter`·`SemaphoreAdmissionController` 다섯 전부 픽스처 애플리케이션에서만 생성**(`testkit/webtestkit/BudgetFixtureApplication:43` 등), main·app-bootstrap 등록 0; `WebBudgetCatalog`는 두 자동설정이 만들고 읽는 코드 0; `backend.web.budgets` 문자열이 자바 한 줄에만 존재해 예외 핸들러는 기본 꺼짐이고 켜면 `BudgetProblemMapper` 빈 부재로 부팅 실패; 배선된 속도 제한은 `RateLimitWebConfig`의 MVC 인터셉터 하나(`APP_RATE_LIMIT_ENABLED:false`) | 리액티브 속도 제한 부재는 인터셉터가 `WebMvcConfigurer`라는 사실에서 도출 |
| SRC-133 | 멱등성 · durable operation 조립 | `evidence/raw/194-inbound-web-idempotency-probes.txt` | same revision | 50/50 FULL_READ; `WebIdempotencyGate`·두 invoker·`IdempotentResponseWriter`·`SemanticRequestFingerprintFactory` 전부 test/testkit에서만 생성, app-bootstrap의 web 멱등성 참조 0(그쪽 `bootstrap/idempotency/*`는 애플리케이션 계층 PostgreSQL 제공자); 두 durable-operation 컨트롤러가 `app.web-platform.durable-operations.enabled`로 게이트되나 그 문자열이 yaml에 없고 `OperationQueryService` 빈도 없음; 의미 지문이 U+001F 구분자 기반이고 길이 프레이밍이 아님 | 지문 충돌은 구성 가능성만 확인, 실제 충돌 생성은 하지 않음 |
| SRC-134 | 표현 계층(페이지네이션·조건부·캐시·버전) | `evidence/raw/195-inbound-web-representation-probes.txt` | same revision | 54/54 FULL_READ; 다섯 패키지 중 소비 모듈이 실제로 부르는 것은 `ETags` 하나(sample-portfolio `WorkLogController` 3곳); **`filter/CacheControlFilter`(`@Component`, 24줄)가 모든 응답에 `Cache-Control: no-store`를 붙여 같은 컨트롤러의 ETag/`If-None-Match` 304 경로를 규격상 무력화**하고, 그것을 조정하도록 설계된 `cache` 패키지 310 LOC은 패키지 밖 참조 0; `UnsupportedApiVersionException`은 main throw 지점 0 | `no-store`와 조건부 읽기의 충돌은 RFC 9111 해석에 근거하며 브라우저 실동작은 확인하지 않음 |
| SRC-135 | JSON 강건화 · 코덱 · OpenAPI | `evidence/raw/196-inbound-web-codec-probes.txt` | same revision | 45/45 FULL_READ; `WebJsonProfile` 8개 필드 중 **7개는 `BoundedJsonFactory`/`WebObjectMapperFactory`가 강제하고 `maxArrayElements`만 독자 0** — Jackson 3 `StreamReadConstraints`에 배열 원소 상한이 없고 매퍼도 검사하지 않음, §16.1의 바이트 예산 부재와 겹쳐 배열 원소 수 상한이 어느 계층에도 없음; `maxStringBytes`가 Jackson의 문자 기준 `maxStringLength`에 매핑; `SecureXmlInputFactory`가 DTD·외부 엔티티를 끄고 거부 리졸버까지 검(`secure()` 자가검사 포함); 배선된 `OpenApiCustomizer``config/OpenApiContractConfig`의 익명 람다 하나이고 `openapi` 패키지 607 LOC은 빈이 되지 않음 | XML/CBOR은 `compileOnly`로 런타임 부재가 의도된 설계 |
| SRC-136 | 필터 체인 · 관측 · 프록시 신뢰 | `evidence/raw/197-inbound-web-observability-probes.txt` | same revision | 53/53 FULL_READ; 배선된 필터 다섯(MVC 자동설정 2 + `@Component` 2 + WebFlux 자동설정 1); **`WebMvcRequestIdFilter`(기본 `trustInboundRequestId=false`, 순서 `HIGHEST_PRECEDENCE+10`)가 UUID를 쓴 뒤 `RequestLoggingFilter`(무순서 → `LOWEST_PRECEDENCE`)가 클라이언트 헤더 값으로 응답 헤더·MDC를 덮어씀**; `HeaderSanitizer``<0x20`을 제거해 로그 인젝션은 아님; `proxy` 패키지 421 LOC 미배선이고 스푸핑 방어는 `nginxProxyTest/resources/nginx/proxy_headers.conf`가 location마다 헤더를 덮어쓰는 데 의존; `server.forward-headers-strategy` 기본값이 `framework` | 프록시 우회 도달 가능성은 배포 토폴로지에 의존하며 이 분석에서 확인하지 않음 |
| SRC-137 | Advanced 능력 카탈로그와 게이트 | `evidence/raw/198-inbound-web-advanced-probes.txt` | same revision | 65/65 FULL_READ; `WebAdvancedFeature` 상수 **11개**, `advanced/**`의 프로덕션 `@ConditionalOnProperty` 접두사 **2개**(`mvc-virtual-threads` · `ndjson`) — 나머지 9개 능력은 프로퍼티도 `@Configuration`도 빈도 없음; `WebAdvancedFeatureFlags`(단일 활성화 표면으로 설계) 프로덕션 독자 0; `VirtualThreadProfile.propertyName()``virtual-threads`(=`mvc-` 누락)를 반환하고 호출자 0; `ndjson` 스위치 하나가 NDJSON과 JSON_SEQUENCE 둘을 켬 | 능력이 off-by-default인 것은 build.gradle이 명시한 설계 |
| SRC-138 | fileserver 조립 · 리액티브 활성화 조건 | `evidence/raw/199-inbound-web-fileserver-probes.txt` | same revision | 73/73 FULL_READ; **이 leaf에서 유일하게 완전히 조립된 하위 트리**`FileserverPlatformAutoConfiguration`이 URI 매퍼·다운로드 전략·요청 컨텍스트 팩토리를 만들고 `FileserverStartupConfiguration:87``attestMapping()`을 시작 시 호출; `DefaultNginxInternalUriMapper`가 앵커 정규식 + 구성 후 `..`/`//`/`\` 재검사; **`@ConditionalOnWebApplication(REACTIVE)`가 걸린 29개 main 파일은 클래스패스가 SERVLET을 고정하므로 활성화 불가**(leaf `build.gradle``spring-boot-starter-web` 선언 · app-bootstrap lockfile에 tomcat/webmvc · sample-portfolio도 starter-web · `setWebApplicationType` main 사용 0) | `WebApplicationType.deduceFromClasspath()` 동작에 근거한 정적 판정 |
| SRC-139 | notification 웹 표면 · admin | `evidence/raw/200-inbound-web-notification-admin-probes.txt` | same revision | 26/26 FULL_READ; `CallbackRequestConfiguration`이 게이트 아래에서 자기 의존을 `@ConditionalOnMissingBean`으로 공급하고 신뢰 프록시 기본값이 빈 집합("Honouring them unconditionally would let any caller choose the URL that gets signature-verified") — **닫힌 옵트인**; `SpringMvcRouteInventoryCollector`(138줄)는 저장소 전체 참조가 자기 파일 2줄뿐(테스트도 0); `WebPlatformStartupValidator`(62줄)는 test 5 · main/boot 0으로 시작 시 실행되지 않음(fileserver의 `attestMapping()`과 대조) | — |
| SRC-140 | testkit · 세 런타임 계약 레인 | `evidence/raw/201-inbound-web-testkit-probes.txt` | same revision | 94/94 FULL_READ; 계약 클래스 7종이 소스셋 분리와 `dependsOn`으로 세 런타임에 강제 적용(notification의 상속 3/8과 대조); `WebArchitectureRules` 7규칙이 app-bootstrap `WebProductionArchitectureTest:47`에서 프로덕션 트리에 적용되고 `WebArchitectureRulesTest:86-88`이 개수를 고정; **픽스처 애플리케이션 9개가 `new`로 세우는 플랫폼 타입 목록이 §16.1·§20.1·§36.1의 미배선 목록과 일치** — 레인이 인증하는 조립은 픽스처의 조립 | — |
| EVD-077 | suite 검증 | `analysis/14-adapter-inbound-web.md` §50.6 | 2026-08-30 | `:adapter:inbound:web:test` + `:webSecurityBoundaryTest``BUILD SUCCESSFUL`, `GRADLE_EXIT=0`, classes=176 tests=1221 failures=0 errors=0 **skipped=0**; 이 모듈의 P1 6건·P2 8건 중 테스트가 검출한 것은 0건; `git status --short` 변경 0 | `webCrossStackParityTest`·`webJettyCompatTest`·`webFluxContractTest`·`webNginxProxyTest`·`webAdvancedTest`는 실행하지 않음(임베디드 서버 2종 다운로드 · Docker 런타임 요구) |
| SRC-141 | 컴포지션 루트 스캔 경계 | `evidence/raw/203-composition-root-scan-boundary.txt` | same revision | `CaSkeletonApplication.AUTO_CONFIGURED_PACKAGES` 정규식이 web leaf의 다섯 패키지(`mvc.error` · `mvc.budget` · `mvc.operation` · `webflux.error` · `webflux.operation`)를 컴포넌트 스캔에서 제외하고 javadoc이 그 이유를 "Ownership by auto-configuration is what ties a control's presence to its dependency's"로 적음; **그 소유권을 넘겨받는 자동설정이 없음**`AutoConfiguration.imports` 2줄 중 어느 것도 해당 타입을 만들지 않고, app-bootstrap의 해당 타입 참조 0, `.imports`/`.factories` 참조 0, `WebProblemFactory` 참조 0. 이 사실이 모듈 14 §8.1의 판정을 "두 계약 공존"에서 "RFC 9457 계약 23파일 미등록"으로 교체 | 정적 판정(정규식 · 등록자 부재); 실제 컨텍스트를 띄워 빈 목록을 확인하지는 않음 |
| SRC-142 | module map / denominator | `evidence/raw/202-inbound-grpc-module-inventory.txt` | same revision | 18 tracked files(main 8 · test 6 · governance 4), main Java 602 LOC · test Java 782 LOC — 단일 bounded scope; build.gradle이 third-party grpc starter 없이 `SmartLifecycle`이 Netty 서버를 직접 소유하는 이유, `.proto`/protobuf 플러그인 부재, `grpc-bom`/`protobuf-bom`을 모듈 스코프에서 import해 strict-locking blast radius를 이 모듈에 가두는 이유를 명시; `registerStrictQualificationTest`가 두 클래스를 이름으로 요구 | 초기 sizing |
| SRC-143 | gRPC 전송 계약 · 활성화 · 에러 매핑 | `evidence/raw/204-inbound-grpc-probes.txt` | same revision | 18/18 FULL_READ; **활성화 삼중 게이트**`@ConditionalOnProperty(matchIfMissing=false)` + `@AssertTrue isInsecureLocalConfigurationValid()`(`!enabled || (allowInsecureLocal && InetAddress.isLoopbackAddress())`) + feature 서비스 존재 시 정확히 하나의 `GrpcAuthenticationPolicy` 요구; `GrpcExceptionHandlingInterceptor`가 네 실패 경로(handler throw · listener throw · `onError` · raw status)를 하나의 sanitizing `close`로 모아 호출자 description·트레일러를 폐기하고 `code`/`category` 트레일러로 재작성; `GrpcStatusMapper.toStatus``Category` 10값을 `default` 없이 전수 처리; **`errorCodeOf`의 종료 조건이 `getCause() == current` 자기참조 검사뿐이라 2-순환에서 무한 루프** — 저장소 전체 9개 순회 지점 중 5개는 깊이 제한, 4개(grpc · `MvcDisconnectDetector` · `WebFluxDisconnectDetector` · `TransactionRetryClassifier`)는 자기참조 검사이며 `JdkNotificationHttpGateway:93-97`이 그 2-순환 사례를 이름으로 적고 깊이 제한을 택한 근거를 남김; `BindableService`·`GrpcAuthenticationPolicy` 구현 0 · `ca-skeleton.grpc` yaml 키 0은 CLAUDE.md가 선언한 상태 | 순환 사슬은 구성 가능성만 확인, 실제 무한 루프 재현은 하지 않음 |
| EVD-078 | suite 검증 | `analysis/15-adapter-inbound-grpc.md` §5 | 2026-08-30 | `:adapter:inbound:grpc:test` + `:grpcTransportQualificationTest``BUILD SUCCESSFUL`, `GRADLE_EXIT=0`, classes=8 tests=48 failures=0 errors=0 **skipped=0**; qualification lane이 `grpcTransportQualificationTest: 15 tests, 0 skipped` 증거를 출력; `GrpcP1BoundaryWireTest`가 실제 loopback ephemeral Netty 서버로 와이어 계약을 확인 | — |
| SRC-144 | module map / denominator | `evidence/raw/205-inbound-graphql-module-inventory.txt` | same revision | 534 tracked files(main 411 · test 103 · testFixtures 16 · governance 4), main Java 26,303 LOC · test Java 13,671 LOC, main 패키지 41개; 11개 sub-scope 분할을 패키지 트리에서 기계 계산(중복 0 · 미할당 0) | 초기 sizing |
| SRC-145 | 패키지 도달성 지도 | `evidence/raw/206-inbound-graphql-package-reachability.txt` | same revision | main 41개 패키지의 `in`(다른 graphql main 패키지가 import) / `ext`(app-bootstrap·sample-portfolio가 import) 기계 산출 — **`ext` 열이 전 패키지 0**이며, 이는 컴포지션 루트가 `dev\.caskeleton\.adapter\.inbound\.graphql\..*`를 컴포넌트 스캔에서 제외하고 조립을 자동설정 진입점 하나에 맡긴 구조와 일치 | import 기반; 자동설정 `@Bean` 참조는 별도 삼중 카운트로 확인 |
| SRC-146 | 조립 진입점 · off 계약 | `evidence/raw/207-inbound-graphql-autoconfigure-probes.txt` | same revision | 60/60 FULL_READ; `.imports` 한 줄이 마스터 게이트를 든 얇은 루트(`GraphQlRootAutoConfiguration`)이고 704줄 플랫폼 설정(39 `@Bean` · 43 `@ConditionalOn`)을 `@Import`; `spring.factories``AutoConfigurationImportFilter`(프레임워크 GraphQL 자동설정 10개를 이름으로 차단)와 `EnvironmentPostProcessor`(은퇴 키 거부 + 콘솔 플래그 기본값 기여)를 건다; off 계약의 두 절반이 app-bootstrap `GraphQlShippedAndGatedTest`(빈 인벤토리 + 실제 포트에서 미매핑 경로와 상태코드 동일성)로 검증됨; **`HealthGraphqlController``@Import`에 있고 그 주석이 "no root imported it ... Its own tests passed throughout by registering the class themselves"로 과거 결함을 기록** — 모듈 14 §8.1과 같은 형태를 여기서는 닫음 | 프레임워크 자동설정 목록은 하드코딩이며 새 항목 추가에 대한 드리프트 검사는 없음 |
| SRC-147 | 스키마 거버넌스 · 스칼라 · 호환성 | `evidence/raw/208-inbound-graphql-schema-probes.txt` | same revision | 46/46 FULL_READ; 파일 단위 삼중 카운트로 `GraphQlScalarWiringConfigurer`(7) · `GraphQlScalarManifest`(4) · `GraphQlMappingInspectionGate`(3) 배선 확인; **`GraphQlSchemaAssembler`·`GraphQlSchemaContract`·`GraphQlOneOfSchemaGate`·`GraphQlOneOfInputValidator` autoconf=0 main_other=0**이고 `GraphQlSchemaHash` 생산 사슬(`assemble → AssemblyResult.schemaHash`)의 유일한 소비자 `GraphQlPlatformActuatorEndpoint``@Bean`이 없음; graphql-java 25.0이 `@oneOf`를 자체 처리 | 조립 순서 불안정의 실제 발현은 조각이 하나뿐이라 관측 불가 |
| SRC-148 | 실행 사슬 · 요청 컨텍스트 · 예산 계층 | `evidence/raw/209-inbound-graphql-execution-probes.txt` | same revision | 60/60 FULL_READ; `runtime` 19종 대부분이 autoconf 2~7로 배선; **설계 §10의 5계층 예산 중 요청 계층만 강제**(`GraphQlPlatformWebInterceptor:135` + `GraphQlRequestContext.withDeadline` 단조 조이기 + `GraphQlCancellation`) 되고 `GraphQlDeadlinePropagator`의 파생 다섯 메서드는 호출자 0 — `GraphQlTimeoutPolicy`·`GraphQlResolverBudget` 참조자가 전부 미배선 클러스터 내부; 익명 연산 거부는 배선된 `GraphQlOperationSelectionHandler`가 네 가지 케이스로 수행 | 다운스트림 데드라인 미전달의 실제 영향은 아웃바운드 어댑터 기본값에 의존 |
| SRC-149 | 비용 제어 · 정책 · 보안 | `evidence/raw/210-inbound-graphql-cost-security-probes.txt` | same revision | 57/57 FULL_READ; 구조 한계·복잡도·관측은 배선(autoconf 4~6); **`GraphQlParserOptionsFactory`(파서 한계를 graphql-java 정적 전역에 설치) 호출자 0** — `backend.graphql.limits.*``GraphQlClientPolicy``GraphQlParserLimits.from(...)` 사슬이 끊김; **`GraphQlClientPolicyManifest` 미배선**이고 자동설정이 `GraphQlClientPolicy.defaults(properties)` 단일 빈을 8곳에 주입 — 자격에서 해석된 프로파일이 예산을 고르지 않음; `GraphQlContextPropagator`는 네 진입점 전부 `finally` 복원으로 누수 없음 | graphql-java 기본 파서 한계가 백스톱으로 작동 |
| SRC-150 | HTTP 전송 계약 · 오류 · 관측 | `evidence/raw/211-inbound-graphql-http-probes.txt` | same revision | 48/48 FULL_READ; **main 전체에 `GraphQlHttpHandler`/`RouterFunction`/`@PostMapping`이 없어 이 leaf는 HTTP 엔드포인트를 소유하지 않음**`/graphql`은 Spring GraphQL이 발행; `http` 19파일 중 값으로 소비되는 둘(`GraphQlHttpProfile` 2 · `GraphQlJsonStructurePolicy` 4)을 뺀 전송 기계는 닫힌 섬; `GraphQlRequestErrorMapper`(파싱·검증 실패 매퍼) 미배선; 관측 9종은 autoconf 3~6으로 배선 | 프레임워크가 GraphQL-over-HTTP 스펙을 구현하므로 동작 자체는 합리적 |
| SRC-151 | DataLoader · 커서 · 뮤테이션 | `evidence/raw/212-inbound-graphql-data-probes.txt` | same revision | 69/69 FULL_READ; `dataloader``GraphQlBatchLoaderRegistrar`(autoconf=4) 경유로 배선; **`backend.graphql.cursor.key-ids`를 읽는 프로덕션 코드가 시작 검증기와 액추에이터 둘뿐이고 서명하는 코드가 없음** — `HmacGraphQlCursorCodec`·`GraphQlCursorKeyRing` autoconf=0 main_other=0; 이 사실을 `autoconfigure/GraphQlPolicyRequestPathTest`(GQL-INT-003)가 javadoc으로 기록하고 "this test fails the moment somebody wires one half without the other"로 고정 | 페이지네이션이 어떤 feature에도 붙지 않아 현재 조작 대상 커서 자체가 없음 |
| SRC-152 | capability 등급표 대조 | `evidence/raw/213-inbound-graphql-release-probes.txt` | same revision | 10/10 FULL_READ; `CLAUDE.md`가 4등급(`modelled`/`wired`/`integration-verified`/`production-verified`)을 정의하고 "현재 등급보다 높게 표현하지 않는다"를 규칙으로 선언, 13행 중 **일곱을 스스로 `modelled`로 강등**; sub-scope 02~06의 파일 단위 배선 데이터와 13행을 전수 대조한 결과 **12행 일치, `요청 크기/Accept 협상 (http/)` 한 행만 불일치** — 인용된 두 증거(`GraphQlRequestBoundsTest`·`GraphQlAcceptNegotiationTest`)가 endpoint 테스트가 아닌 순수 단위 테스트이고 대상 타입은 autoconf=0; `GraphQlStableCapabilityManifest.STABLE``SIGNED_CURSOR_CONNECTION`을 포함해 등급표(`modelled`)와 불일치 | 등급표는 사람이 읽는 문서, 매니페스트는 `requireStable`이 소비하는 기계 판정 |
| SRC-153 | Advanced 3개 sub-scope | `evidence/raw/214`·`215`·`216-inbound-graphql-advanced-*-probes.txt` | same revision | 163/163 FULL_READ(51+53+59); **141개 Advanced main 파일 전부 autoconf=0**이고 등급표의 `modelled` 선언과 일치; 타입 이름이 등급을 인코딩(`*Admission` — "Spring transport handler 는 없다(그래서 타입 이름도 `*Admission` 이다)"); `*HandlerFactory` 세 종은 "Decides whether the handler may exist, and on what terms"로 판정만 수행; `advanced/springdata``UNSUPPORTED`로 강등되며 "a capability flag cannot make an architectural rule conditional" 근거 기록; `GraphQlAdvancedFeatureFlags``@ConfigurationProperties`가 아니라 정적 팩토리만 가져 활성화 설정 표면이 없음 | Advanced 진입점이 `.imports`에 없음 — 등급표는 이를 `modelled`로 인정 |
| EVD-079 | suite 검증 | `analysis/16-adapter-inbound-graphql.md` §45.4 | 2026-08-30 | `:adapter:inbound:graphql:test``BUILD SUCCESSFUL`, `GRADLE_EXIT=0`, classes=186 tests=1603 failures=0 errors=0 **skipped=0** | `graphqlStableTest`(605) · `graphqlContractTest`(9) · `graphqlAdvancedTest`(152) 세 플랫폼 레인은 실행하지 않음 |
| SRC-154 | module map / denominator | `evidence/raw/218-inbound-websocket-module-inventory.txt` | same revision | 253 tracked files(main 169 · test 67 · testkit 7 · nginxWebSocketTest 4 · jettyWebSocketTest 1 · brokerRelayTest 1 · governance 4), main Java 12,784 LOC · test Java 9,435 LOC, main 패키지 39개; `META-INF` 자동설정 리소스 없음 — 조립이 전적으로 컴포넌트 스캔에 달림 | 초기 sizing |
| SRC-155 | 세 설정 네임스페이스와 조립 지점 | `evidence/raw/219`~`226-inbound-websocket-*-probes.txt` | same revision | 253/253 FULL_READ; **169개 main 파일 중 Spring 애노테이션을 가진 것이 7개**이고 설정 접두사가 셋으로 갈림 — `ca-skeleton.websocket.*`(`stomp/WebSocketConfig`가 소비, 실제 동작) · `app.websocket-platform.advanced.*`(4개 `@Configuration`) · **`backend.websocket.*`(`WebSocketPlatformSettings`, 소비 `@Configuration` 0)**; 세 접두사 모두 어떤 application.yml에도 없음; `WebSocketPlatformStartupValidator`(125)와 `WebSocketStackExclusivity`(78) 프로덕션 호출자 0 — 후자는 inbound-web §40.1(서블릿/리액티브 이중 스택에서 리액티브 엔드포인트가 조용히 응답하지 않는 상태)을 이름 붙여 탐지하는 클래스; CLAUDE.md Responsibility 5줄·Typed settings 4키가 `stomp` 8파일만 서술하고 Evidence 절의 면책("Broker relay, multi-node/durable delivery, rollback-safe publication, replay/resume, backpressure ... are not claimed")이 `advanced/stomp/rabbit`(7)·`cluster`(9)·`resume`(8)·`outbound`(8)를 덮되 90개 플랫폼 파일은 덮지 않음 | evidence 파일의 `autoconf` 열은 graphql 스크립트 재사용으로 이 leaf에서는 전 행 0이며 정보가 없음 — 배선 판정은 애노테이션 전수와 `main_other` 열로 수행 |
| EVD-080 | suite 검증 | `analysis/17-adapter-inbound-websocket.md` §26.5 | 2026-08-30 | `:adapter:inbound:websocket:test``BUILD SUCCESSFUL`, `GRADLE_EXIT=0`, classes=91 tests=720 failures=0 errors=0 **skipped=0**; P1(§4.1)은 720개 전부 통과 상태에서 나옴 | 커스텀 레인 4종(`websocketNginxTest`·`websocketBrokerRelayTest`·`websocketAdvancedTest`·`websocketJettyTest`)은 Docker·별도 서버·외부 브로커를 요구해 실행하지 않음 |
| SRC-156 | module map / denominator | `evidence/raw/227-app-bootstrap-module-inventory.txt` | same revision | 455 tracked files(main 157 · test 288 · functionalTest 4 · sampleOffTest 1 · conditionalTransportTest 1 · governance 4 · resources 7), main Java 12,380 LOC · **test Java 32,568 LOC(main의 2.6배)**; 조립 표면 전체가 네 리소스 파일 — `.imports` 6줄 · `spring.factories`(EnvironmentPostProcessor 6 · SpringBootExceptionReporter · AutoConfigurationImportFilter · ApplicationListener) · ManagementContextConfiguration `.imports` 1줄 · `CaSkeletonApplication`의 두 스캔 | 초기 sizing |
| SRC-157 | 활성화 모델과 런타임 멤버십 | `evidence/raw/228-app-bootstrap-activation-probes.txt` | same revision | 62/62 FULL_READ; `shared-contract``MasterSwitch` enum이 다섯 어댑터(jpa·mongo·messaging·notification·graphql)의 프로퍼티·환경변수를 SSOT로 갖고 네 장치를 구동 — 값 문법 거부(`MasterSwitchEnvironmentPostProcessor`) · 능력 의존 검증(`CapabilityDependencyValidator` 156) · 액추에이터 보고(`AdapterActivationReport`, "the application's answer" ) · 삼자 일치 테스트(enum ↔ `docs/registries/env-keys.yaml``application.yml`, "a sixth adapter cannot be added without this test demanding its row"); **`modules.json``runtime_memberships`가 grpc=[] · websocket=[] · graphql=["app-bootstrap"] · web=["app-bootstrap","sample-portfolio"]** 이고 `ConditionalTransportCompositionContractTest`가 grpc·websocket을 BUILD_ONLY_TRANSPORTS("nothing may put them on a runtime")로 기계 강제 — 두 어댑터가 활성화 모델 밖인 것은 누락이 아니라 일관성; 남는 것은 출하되는 web의 스위치 넷(`backend.web.mvc`·`webflux` 기본 켜짐 포함)이 모델 밖이라는 점 | 이 확인으로 모듈 17 §4.1을 P1 → P2로 하향(모듈 17 §26.6) |
| SRC-158 | 시작 검증기 배선과 조립 규칙 | `evidence/raw/230-app-bootstrap-runtime-probes.txt` | same revision | 85/85 FULL_READ; **runtime 검증기 12종 전부 배선**(`RuntimeSafetyConfig` `@Bean` 7 · `SecretSourceConfig` · `MigrationStartupConfig`), `StartupFailures`(75)가 구조화 실패 로그의 단일 발생원이며 종료 코드까지 규정(STARTUP_VALIDATION_FAILED=78 · MigrationFailed=70); main 157 파일에 **고아 0** — 참조 0인 파일은 전부 `@Configuration` 루트 · logback 컴포넌트(`logback-spring.xml`이 클래스명으로 등록) · `spring.factories` 항목으로 설명됨; **시작 검증기가 도는지 여부가 그 능력에 자동설정 루트가 있는지와 정확히 일치**(app-bootstrap 12종·fileserver attest·graphql 검증기는 배선, web·websocket 검증기는 미배선) | — |
| SRC-159 | 아키텍처 규칙 · 계약 레인 | `evidence/raw/233`·`234`·`235-app-bootstrap-*-probes.txt` | same revision | 172/172 FULL_READ(90+54+28); 아키텍처 규칙 14종이 프로덕션 트리에 적용되고 **위반/허용 합성 픽스처 76개**가 각 규칙의 양방향을 고정; 계약 테스트 30종이 레지스트리 일치·관측/로그·보안 표면·활성화·실패 분류·운영을 덮고 `ContractSuiteCompletenessTest`가 스위트 자체의 완전성을 검사; `dev.caskeleton.onboarding.**` 14파일이 "새 feature 추가 절차"의 합성 대상; 대체 소스셋 3종(functionalTest 4 · sampleOffTest 1 · conditionalTransportTest 1) | — |
| EVD-081 | suite 검증 | `analysis/18-app-bootstrap.md` §26 | 2026-08-30 | `:app-bootstrap:test` → `GRADLE_EXIT=1`, classes=169 tests=1016 **failures=1** errors=0 skipped=4; 유일한 실패 `ComposeMergeCharacterizationTest.everyLaneMatchesItsContract`는 **환경 원인**(분석 컨테이너에 `jq` 없음 → `verify-compose-profile-contracts.sh` exit 78); 같은 테스트가 `docker compose` 부재는 `Assumptions.assumeTrue`로 skip하고 `jq` 부재는 실패로 처리하는 가드 비대칭을 P3로 기록 | 나머지 1,015개 통과 |
| SRC-160 | family map / denominator | `evidence/raw/251-messaging-leaf-registry-and-memberships.txt` · `243-messaging-core-contracts-inventory.txt` | same revision | `modules.json`에서 `gradle_path`가 `:messaging:`인 leaf **25개** 전량 열거 + 각 `source_path`에 `git ls-files` — leaf 합계 549, `src/messaging` 전체 550(차이는 가족 공통 `CLAUDE.md` 1개), 미배정 0; **출하 18 / build-only 7**(testkit · pulsar · nats · scs-bridge · schema-avro · kafka-share · schema-protobuf); 등록 id 주의 — `messaging-inbox-jdbc-postgresql` / `messaging-outbox-jdbc-postgresql` / `messaging-cloudevents`(schema 접두사 없음), 디스크의 `-inbox-jpa`·`-outbox-jpa`는 추적 파일 0으로 분모 밖 | 이 18/7 구분이 문서 전체의 심각도 축(모듈 17 §26.6 원칙 적용) |
| SRC-161 | 공개된 주장의 검증 | `evidence/raw/244-messaging-fault-scenarios-vs-evidence.txt` · `246-messaging-mss022-no-string-matching.txt` · `250-messaging-certification-gate-chain.txt` | same revision | `src/messaging/CLAUDE.md`의 Stable 승격 조건 중 코드로 검증 가능한 3개 전부 **성립**; MSG-022(예외 타입 문자열 판별) 25 leaf main 전체 0건; `NetworkFaultScenario` 5개 중 Kafka 증거 4개이고 미커버 `connection-refused`는 `CertifiedEvidence.knownGaps`가 `all() - covered`로 **파생**하며 `aScenarioWithNoLineInTheManifestIsAGapRatherThanAnAbsence`가 이유까지 단언; `verifyMessagingCertificationEvidence`가 실행 산출물 ↔ 커밋 manifest를 **양방향** 대조(`gitCommit`·`observedAt`은 정규식 제거 후 비교, `upToDateWhen{false}`, CI가 `src/messaging/**` PR마다 실행) — manifest의 `gitCommit: e98b56eb03ec`가 분석 리비전보다 오래된 것은 설계상 정상 | 19개 모듈 중 공개 주장이 검증을 그대로 통과한 첫 사례 |
| SRC-162 | capability 집행 · profile validator 도달성 | `evidence/raw/247-messaging-capability-flag-enforcement-census.txt` · `248-messaging-profile-validator-reachability.txt` · `249-messaging-startup-profile-validation.txt` | same revision | `MessagingCapabilities` 12개 플래그의 main/test 참조 전수 — main이 읽는 것 **3개**(`orderedStream`·`delayedDelivery`는 분기, `deduplicatedPublish`만 거부), 나머지 9개는 모든 어댑터가 선언하고 아무 곳도 읽지 않음(census의 `orderedStream` main=5 중 4건은 Spring `ObjectProvider.orderedStream()` 오탐); javadoc의 "fails loudly — at startup where possible"가 성립하지 않음; profile validator **8개 중 조립 3개**(`DestinationProfileValidator`·`KafkaProfileValidator`·`RabbitProfileValidator`) — 미조립 5개 중 4개는 build-only leaf라 등급 일치이고 **출하 leaf의 `KafkaTransactionProfileValidator`만 결함**(`@Bean` 선언만, 주입처 없음); `StartupProfileValidation` javadoc이 같은 결함을 이미 한 번 고친 이력을 서술 | `PulsarProfileValidator`는 테스트조차 0건 |
| SRC-163 | schema · 관측 도달성 | `evidence/raw/252-messaging-schema-and-observability-reachability.txt` · `253-messaging-observation-assembly.txt` · `254-messaging-autoconfiguration-imports.txt` | same revision | 출하 leaf의 main 참조 0 타입 — `SchemaCompatibilityValidator`(+`SchemaRegistry` main 구현 없음, `DestinationSettings`가 `NONE_EXPERIMENTAL` 설정을 허용), `DefaultCloudEventMapper`(출하 leaf이자 starter `implementation` 의존인데 소비자 0), `MessagingMetrics`·`MessagingTracer`·`MessagingAuditSink`·`DefaultMessagingObservationConvention`; `MessagingCoreAutoConfiguration`이 관측 관련으로 등록하는 것은 `MessagingRedactor`·`CardinalityGuard` **협력자 둘뿐**이고 `messagingPublisher`가 6인자 생성자를 골라 `NO_OBSERVATION`을 주입 — `DefaultMessagePublisher` 필드 javadoc의 "an unobserved publish path is how 'the dashboards were empty during the incident' happens"가 조립에서 되돌려짐; `AutoConfiguration.imports`는 `MessagingPlatformRootAutoConfiguration` 1줄 | 자동설정 클래스 28개, 그중 `.imports`에 오르는 것은 루트 하나 |
| SRC-164 | 문서 ↔ 코드 capability 전수 대조 | `evidence/raw/255-messaging-capability-doc-vs-code-drift.txt` | same revision | `docs/messaging/support-matrix.md` capability 표 60칸(5 어댑터 × 12 플래그)을 각 어댑터의 `MessagingCapabilities` 배열과 전수 대조 — **불일치 1칸**: Kafka `deduplicatedPublish`가 문서 `O`, 코드 `false`; 그 플래그가 12개 중 유일하게 거부를 발생시키는 것이고, `KafkaMessagingTransport`의 javadoc이 true→false 변경 이력과 "the caller believes the broker is deduplicating and skips the idempotency it would otherwise build"라는 피해를 서술; Rabbit·Kafka Share·Pulsar·NATS 48칸 전부 일치(Pulsar `keyedOrdering`은 SHARED/KEY_SHARED 두 배열 차이까지 문서가 반영); Rabbit `delayedDelivery`는 코드 `true` / 문서 `retry queue로 대행`으로 문서가 더 정확 | 이 문서 유일의 P1 |
| SRC-165 | 전송 선택 · Rabbit 조립 · MSG-015 | `evidence/raw/256-messaging-provider-selection-and-rabbit-transport.txt` · `257-messaging-msg015-two-kafka-stacks.txt` | same revision | `MessagingPlatformRootAutoConfiguration`이 `app.messaging.enabled=true`를 `matchIfMissing` 없이 단독 소유하고 자식은 조건을 갖지 않음 — 모듈 14 §8.1이 web에서 없다고 판정한 구조를 messaging은 보유; `MessagingProviderSelection.BROKERS_WITHOUT_A_TRANSPORT`에 **rabbit** 등록(`RabbitChannelPublisher` 구현 0건, `RabbitMessagingAutoConfiguration`에 `MessagingTransport` bean 없음) — 코드는 fail-closed로 정직하나 `support-matrix.md`의 RabbitMQ 행 "제한" 칸이 이를 말하지 않음; MSG-015는 bean 이름 분리로 **증상만** 사라짐 — `KafkaSenderConfig`는 `app.messaging.broker=kafka`만 보고 `enabled`를 보지 않아 CLAUDE.md가 말한 기본값 보호(`enabled=false`)가 두 스택 중 하나만 막음 | 오늘 실제 배포 가능한 브로커는 Kafka 하나 |
| SRC-166 | reliability · admin 도달성 | `evidence/raw/258-messaging-reliability-and-admin-reachability.txt` · `260-messaging-admin-plane-assembly.txt` | same revision | `MessagingReliabilityAutoConfiguration`의 조건 사슬 뿌리가 `OutboxRepository`/`InboxRepository` bean인데 유일 구현 `JdbcOutboxRepository`·`JdbcInboxRepository`의 main 참조가 **0** — relay·worker·lifecycle·cleanup·transactional inbox handler 전부 미조립(19 main 파일 2,818 LOC); `MessageCodecRegistry`에는 `@ConditionalOnMissingBean` 기본 구현을 제공한 같은 starter가 여기서는 만족되지 않는 `@ConditionalOnBean`을 남김; claim-check 배선 0; admin plane은 `app.messaging.admin.enabled=true` fail-closed에 `DestructiveOperationGuard(false)`·비내구 journal + `MessagingAdminDurabilityValidator`(production 프로파일 거부, 공급할 클래스 이름을 메시지에 포함)로 **가드는 우수**하나 `DefaultMessagingAdminService`·`HmacApprovalVerifier`·`TopologyValidationRuntime` main 참조 0 — 부재 4건 중 `DestructiveMessagingAdmin` 하나만 javadoc으로 설명됨 | admin 게이트는 이 저장소에서 가장 잘 조립된 축에 속함 |
| SRC-167 | Flyway 마이그레이션 네임스페이스 | `evidence/raw/259-messaging-flyway-migration-namespace.txt` | same revision | 합성 루트의 기본 Flyway 위치는 `PostgreSqlPersistenceConfig:115`의 `classpath:db/migration/postgresql`이고 조건부 스트림은 각자 위치·history table 보유; **`db/migration/messaging`을 이름으로 부르는 main 코드가 저장소 전체에 0건** — `messaging_outbox`·`messaging_inbox`·admin journal 테이블은 어떤 출하 배포에서도 생성되지 않음; 두 leaf가 **같은 리소스 디렉터리에 각자 번호를 매겨 `V2`가 둘**(`V2__messaging_inbox.sql` CREATE TABLE vs `V2__messaging_outbox_lease_fencing.sql` ALTER×4) — 그 위치를 Flyway에 주는 순간 duplicate version으로 부팅 실패; 각 leaf의 IT는 자기 jar 리소스만 보므로 재현 불가; 원래 구현 계획서(plan:3010·3011·3032·3055)는 `messaging-outbox`/`messaging-inbox` 분리 위치를 지정했음 | `persistence-jpa`가 세 번 고친 "bean은 있고 테이블은 없다"의 정반대 형태 |
| SRC-168 | 문서 계약 테스트 커버리지 · 설정 위생 | `evidence/raw/261-messaging-documentation-contract-test-coverage.txt` · `262-messaging-starter-configuration-validators.txt` | same revision | `MessagingDocumentationContractTest`가 doc rot를 막기 위해 존재하고("the only signal is an operator making a decision on a page that stopped being true months ago") 단언 8개를 가짐 — 등급 이름·Kafka 버전·존재하지 않는 두 상수는 정확히 붙들고, **capability 표·runtime membership 문장·브로커 등급표의 "제한" 칸은 커버리지 밖**이며 이 문서가 찾은 문서 드리프트 3건이 전부 그 밖에 위치; 약한 단언 둘(`theExperimentalPolicyStatesThatExperimentalIsOffByDefault` = `contains("false")`, `everyDocumentHasContent` = 500자 초과); starter는 시작 검증기 6종을 실제로 실행 — `MessagingPrefixMigrationValidator`(죽은 세 네임스페이스) · `MessagingConfigurationKeyValidator`(적법 키를 settings record에서 **파생**) · `MessagingCredentialRequirementValidator`(production 한정) · `MessagingAdminDurabilityValidator` · Kafka/Rabbit `StartupProfileValidation` 2종 | `MessagingPublicSurfaceContractTest`는 `src/messaging` 밖(app-bootstrap) 레인에 있음 |
| EVD-082 | suite 검증 | `analysis/19-messaging-platform.md` §12.1 | 2026-08-31 | 25개 messaging leaf의 `:test` 전량 → `BUILD SUCCESSFUL in 2m 27s`, `GRADLE_EXIT=0`, 105 actionable tasks(59 executed · 46 up-to-date); XML 집계 classes=110 tests=851 failures=0 errors=0 **skipped=0**; `git status --short` 출력 없음 | `messagingCertificationTest`/`verifyMessagingCertificationEvidence`(Docker 필수, 의도적으로 가드 없음)와 Testcontainers 계열 IT는 실행하지 않음 |
| SRC-169 | 리비전 이동 · 분모 재확정 | `evidence/raw/264-cross-scope-autoconfiguration-roots.txt`(이동 전) · `265`·`268`(이동 후) | `21234e38` | 교차 스코프 준비 중 레지스트리 전수 재독으로 **등록 62 / state.json 44** 불일치 발견. 원인은 분석 누락이 아니라 리비전 이동 — 기준선 `a24ece9c` 이후 `21234e38`("feat: grpc 기능 deep 구현", 2026-08-31)이 gRPC 가족을 추가했다. `git diff a24ece9c..HEAD` = 400 files / +40,217 / 4이고 변경 경로는 `src/grpc*` · `modules.json`(18항목 추가) · `src/build.gradle`(테스트 클래스패스 조건) · docs 15개뿐 — **`src/messaging` 이하 무변경, 모듈 01~19 전부 유효**; `state.json`의 `gitRevision`을 HEAD로 올리고 `reanalysis`를 `ADDITIVE_SCOPE`로 채운 뒤 18 스코프 추가 | evidence 264는 이동 전 트리(`.imports` 7 · leaf 44), 265·268은 이동 후(`.imports` 8 · leaf 62) |
| SRC-170 | grpc family map / denominator | `evidence/raw/266-grpc-family-claims-verification.txt` | same revision | 18 leaf · 추적 383(leaf 381 + 가족 CLAUDE.md 2) · main Java 260 / 18,726 LOC · test Java 74; **18개 전부 `runtime_memberships: []`** — 가족 전체 build-only이고 이것이 심각도 축(모듈 17 §26.6 원칙); `adapter-inbound-grpc`의 `allowed_dependencies`가 `[domain-core, application-core, shared-contract]`로 이 가족을 볼 수 없음 — messaging MSG-015 재발 방지가 레지스트리로 성립 | 6개 sub-scope, 미배정 0 |
| SRC-171 | 공개 주장 검증 (6건 성립) | `evidence/raw/266-grpc-family-claims-verification.txt` | same revision | `grpc-core-api`의 io.grpc 참조 3건은 **전부 javadoc 산문**이고 `build.gradle`의 `dependencies {}`가 **비어 있어** framework-free가 클래스패스로 강제됨(32 main / 1,897 LOC); Stable→advanced 금지가 레지스트리 0위반 · 소스 0참조 · `verifyCleanArchitectureDependencies` · `GrpcStableBuildInvariant` 네 층 일치; `GrpcEvidenceGrade.requireCertifies`가 CONTRACT 등급의 `tls` 주장을 런타임 거부(등급 집합을 필드가 아니라 `switch`로 계산); 성능 레인 `excludeTags 'grpc-performance'`; 지원 매트릭스가 "Not released … build-only"와 미해결 게이트 입력 2건을 스스로 공시 — **모듈 19 §6.4(messaging 매트릭스의 반대 주장)와 정반대 사례**; `GrpcCompatibilityMatrix.caSkeleton()` 7레인이 문서 표와 전수 일치 | Spring Boot 4.0.8 · UDS resolver 존재도 문서와 일치 |
| SRC-172 | 조립·릴리스 게이트 도달성 | `evidence/raw/267-grpc-family-reachability.txt` · `268-grpc-assembly-and-release-gate.txt` | same revision | 유일한 조립 지점 `GrpcPlatformAutoConfiguration`(`.imports` 1줄, `matchIfMissing=false` fail-closed)이 `@Bean` **9개**를 등록하는데 전부 프로파일·정책이고 서버·인터셉터 체인·서비스 어댑터가 없음; **`GrpcPlatformStartupValidator` main 참조 0**(static 메서드, 호출자 없음)인데 CLAUDE.md는 "startup을 거부한다"고 현재 시제 서술 — 모듈 14 §44.2·17 §4.1·19 §3.5에 이은 네 번째이자 **자동설정 루트가 있는데도 부르지 않는 첫 사례**; `GrpcReleaseEvidence` 생성 지점 4개가 전부 `GrpcStableReleaseGateTest`이고 `runbookPresent` 등 5성분이 호출자 제공 boolean — messaging이 manifest 파일 + Gradle 태스크 + CI 워크플로 3층으로 이미 닫은 모양의 재발; `src/grpc*/*/build.gradle`의 `tasks.register` **0건**, 28개 CI 워크플로 중 grpc 언급 **0건**; main 260 중 참조 0이 73개(공개 API 표면 포함)이고 그중 조립·기계 타입 15종이 결함 | `GrpcServerInterceptorChain` javadoc이 "every codebase gets it backwards at least once"라 적고 조립에서 안 쓰임 |
| SRC-173 | 증거 레인의 실행 경로 | `evidence/raw/268-grpc-assembly-and-release-gate.txt` | same revision | `ca.strict-test-lane.gradle`이 레인을 `verification` 그룹 `Test` 태스크로 **등록만** 하고 `check`에 연결하지 않음(check-dependsOn 0건); CI는 `ci-quality-gates.yml:50`의 `./gradlew check`로 각 leaf 기본 `test`만 커버; 따라서 CONTRACT/TRANSPORT/FAULT 등급을 뒷받침하는 **25개 테스트**(7+9+9)가 누군가 명령을 직접 입력할 때만 실행됨 — 직접 실행해 전부 통과 확인(BUILD SUCCESSFUL, exit 0); 모듈 18 §4.1c의 "a gate that is red in a lane nobody runs locally…"가 그대로 적용되되 이쪽은 오늘 초록 | messaging은 같은 제외에 전용 CI 워크플로라는 대체 경로가 있음 |
| EVD-083 | suite 검증 | `analysis/20-grpc-platform.md` §6.1 | 2026-08-31 | 18개 grpc leaf `:test` 전량 → `BUILD SUCCESSFUL in 1m 12s`, `GRADLE_EXIT=0`, 81 actionable tasks; XML 집계 classes=71 tests=579 failures=0 errors=0 **skipped=0**; 증거 레인 3종 직접 실행 → `BUILD SUCCESSFUL`, exit 0 (inProcess 7 · netty 9 · fault 9, 전부 0 실패 0 skip, Netty는 실제 소켓); `git status --short` 출력 없음 | `grpcPerformanceTest`는 공유 러너 측정이 baseline이 될 수 없어 미실행 |