# 능력 선언 — 제약을 평범한 문자열로만 담는 이유
 * <p>Constraints are plain bounded strings on purpose. A capability record must stay serialisable
 * into a report and safe to publish through an actuator endpoint, so it never stores a provider
 * object — no {@code DataSource}, no {@code EntityManagerFactory}, no Hibernate {@code
 * SessionFactory}. Holding one would drag a live resource into a value type and let a report leak a
 * JDBC URL or credentials.
 */
public record CapabilitySupport(
    JpaCapability capability, SupportLevel level, List<String> constraints) {
#   컴팩트 생성자가 강제하는 것
  public CapabilitySupport {
    Objects.requireNonNull(capability, "capability");
    Objects.requireNonNull(level, "level");
    constraints = List.copyOf(Objects.requireNonNull(constraints, "constraints"));
    for (String constraint : constraints) {
      if (constraint == null || constraint.isBlank()) {
        throw new IllegalArgumentException("capability constraint must not be blank");
      }
    }
  }

# 특권 리포트 — 담지 않는 것이 정의다
 * <p>Deliberately narrow: the connected role, the schema search path, and two privilege answers.
 * There is no JDBC URL, no password, and no host — this record is designed to be safe to surface in
 * an actuator endpoint, and anything that would have to be masked before publishing does not belong
 * in it at all.
 */
public record DatabasePrivilegeReport(
    String currentUser, String searchPath, boolean canCreateInSchema, boolean canCreateInDatabase) {

# 밖으로 나가는 리포트 — 담을 수 없는 것
/**
 * What the JPA platform is willing to say about itself over HTTP (design §37).
 *
 * <p>The interesting part of this type is what it cannot hold. There is no JDBC URL, no username,
 * no password, no SQL, and no entity catalog — an actuator endpoint is reachable by anyone who
 * reaches the management port, and every one of those would be a free reconnaissance answer.
 *
 * <p>What it does report is what an operator actually needs during an incident: which database
 * major version is behind this instance, which provider, which schema version, and whether the
 * safety properties this platform depends on are holding.
#   그 리포트가 특권 리포트를 담는 방식과, 그 불리언이 실제로 계산하는 것
  /**
   * Builds the report, deriving only bounded values from the privilege report.
   *
   * <p>The privilege report's {@code currentUser} and {@code searchPath} are deliberately reduced
   * to a single boolean here: an operator needs to know the runtime role passed verification, not
   * which role it is.
        openInViewDisabled,
        privileges != null && !privileges.holdsCreatePrivilege(),
        capabilities);
#   역할 이름과 search_path 를 검사하는 정책의 main 호출자: 0

# 두 리포트의 컴포넌트 선언부에 있는 provider/자격증명 식별자 수
  JpaPlatformReport.java: 0
  DatabasePrivilegeReport.java: 0

# 그 리포트를 내보내는 엔드포인트
20:@Endpoint(id = "jpaplatform")
30:  @ReadOperation
  @WriteOperation / @DeleteOperation / @Selector 매치: 0
 *
 * <p>Read-only by construction: there is no write operation and no parameter. An endpoint that
 * could trigger a migration, a repair, or a cache eviction would be an admin capability reachable
 * over HTTP by whoever reaches the management port, which is exactly the boundary design §8.4 puts
 * those operations behind.

# 다만 그 엔드포인트는 지금 노출되지 않는다
  저장소에서 'jpaplatform' 이 나오는 곳: 1
JpaPlatformEndpoint.java:20:@Endpoint(id = "jpaplatform")
  출하 설정의 노출 목록
258:        include: health,prometheus,info,loggers,adapteractivation
259-        # D2/D4/D5: explicitly excluded dangerous endpoints (env leaks secrets,
260-        # heapdump/threaddump = memory forensics, shutdown = remote kill, configprops = secret leak).
  등록 지점이 그것을 적어 둔다
   *
   * <p>{@code @Endpoint} alone registers nothing; exposure is still governed by the application's
   * existing {@code management.endpoints} policy, which this deliberately does not widen.
