# 문서가 무엇을 막겠다고 하는가 — 두 가지다
7:/**
8: * The rules a dynamic {@link Specification} query must satisfy before it runs (design §23.2).
9: *
10: * <p>A specification with no predicate is a full table scan wearing a builder's clothing. It is
11: * usually the result of every optional filter being absent — a search screen submitted empty — and
12: * it looks harmless in code review because no single line is wrong. Requiring either a predicate or
13: * an explicit "yes, scan everything" token makes that case a decision instead of an accident.
14: *
15: * <p>A page bound is required for the same reason: an unbounded collection query hydrates whatever
16: * the table happens to hold today.
17: */
# 실제 검사
31:  public static void requireBounded(
32:      Specification<?> specification, Pageable pageable, String allowUnboundedToken) {
33:    Objects.requireNonNull(pageable, "pageable");
34:    if (pageable.isUnpaged()) {
35:      throw new IllegalArgumentException(
36:          "a specification query requires a bounded page; unpaged reads whatever the table holds");
37:    }
38:    if (specification == null && !ALLOW_UNBOUNDED_TOKEN.equals(allowUnboundedToken)) {
39:      throw new IllegalArgumentException(
40:          "a specification query requires a bounded predicate, or the explicit '"
41:              + ALLOW_UNBOUNDED_TOKEN
42:              + "' token");
43:    }
44:  }
45:
46:  /** Fails when the specification has no predicate at all. */
47:  public static void requirePredicate(Specification<?> specification) {
48:    if (specification == null) {
49:      throw new IllegalArgumentException("a specification query requires a bounded predicate");
50:    }
51:  }

# 이 타입을 언급하는 곳 (레포 전체, 언어 무관)
docs/superpowers/plans/2026-08-11-jpa-persistence-platform-implementation-plan.md:1848:- Create: `modules/jpa/jpa-spring-data/src/main/java/io/backend
docs/superpowers/plans/2026-08-11-jpa-persistence-platform-implementation-plan.md:1922:git add 'modules/jpa/jpa-querydsl/src/main/java/io/backend/skel
docs/architecture/jpa-api-surface.txt:321:dev.caskeleton.adapter.outbound.persistence.springdata.SpecificationPolicy
docs/study/postgresql-jpa-walkthrough.ko.md:874:`SpecificationPolicy`:
docs/study/postgresql-jpa-walkthrough.ko.md:3249:SpecificationPolicy
docs/study/postgresql-jpa-walkthrough.ko.md:3257:grep -rn "UpsertExecutor\|WorkClaimExecutor\|RangeQuerySupport\|SpecificationPolicy\|PgRangeJdbcType"
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/springdata/SpecificationPolicy.java:18:public final cla
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/springdata/SpecificationPolicy.java:23:  private Specif
#   두 검사 메서드를 부르는 코드 (정적 임포트 포함, 레포 전체): 0

# 같은 리프의 형제 정책. 같은 토큰을 쓰고 같은 널 비교를 한다.
adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/springdata/SpecificationPolicy.java:21:  public static final String ALLOW_UNBOUNDED_TOKEN = "allow-unbounded-scan";
adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/querydsl/PredicatePolicy.java:20:  public static final String ALLOW_UNBOUNDED_TOKEN = "allow-unbounded-scan";
29:  public static void requireBounded(Predicate predicate, QueryPage page) {
30:    Objects.requireNonNull(page, "page");
31:    if (predicate == null && !page.allowsUnboundedScan()) {
32:      throw new IllegalArgumentException(
33:          "a collection query requires a bounded predicate, or the explicit '"
34:              + ALLOW_UNBOUNDED_TOKEN
35:              + "' token");
36:    }
#   형제 쪽 호출처와 그것을 부르는 테스트
adapter/outbound/persistence-jpa/src/test/java/dev/caskeleton/adapter/outbound/persistence/querydsl/QuerydslJpaSupportTest.java:17:    assertThatThrownBy(() -> PredicatePolicy.requireBounded(null, QueryPage.of(0, 100)))
adapter/outbound/persistence-jpa/src/test/java/dev/caskeleton/adapter/outbound/persistence/querydsl/QuerydslJpaSupportTest.java:25:    assertThatCode(() -> PredicatePolicy.requireBounded(null, QueryPage.unboundedScan(0, 100)))
adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/querydsl/QuerydslJpaSupport.java:42:    PredicatePolicy.requireBounded(predicate, page);
