# 이 타입이 존재하는 이유
  BoundScopedOperations.java:12 /**
  BoundScopedOperations.java:13  * {@link ScopedMongoOperations} over one physical collection.
  BoundScopedOperations.java:14  *
  BoundScopedOperations.java:15  * <p>Every method passes the collection this scope was built with. That is the whole implementation
  BoundScopedOperations.java:16  * and the whole point: a caller cannot supply a different one, so the registered collection profile
  BoundScopedOperations.java:17  * and any tenant boundary derived from it hold without the caller having to cooperate.
  BoundScopedOperations.java:18  *
  BoundScopedOperations.java:19  * <p>Every query-shaped method also carries the operation's deadline as {@code maxTimeMS}, and that
  BoundScopedOperations.java:20  * is the difference between a deadline and a report about one. The blocking executor could only
  BoundScopedOperations.java:21  * measure elapsed time after the callback returned — a Java callback cannot be interrupted mid
  BoundScopedOperations.java:22  * driver call — so an operation that ran past its budget was detected, never stopped. Sent to the
  BoundScopedOperations.java:23  * server, the same number ends the work.
  BoundScopedOperations.java:24  *
  BoundScopedOperations.java:25  * <p>It applies to the methods that take a {@link Query} or an {@link Aggregation}, because those
  BoundScopedOperations.java:26  * are the ones the server can cut short. {@code insert} carries no query to attach it to.
  BoundScopedOperations.java:27  */
  그 데드라인이 실제로 붙는 자리 :
    BoundScopedOperations.java:19  * <p>Every query-shaped method also carries the operation's deadline as {@code maxTimeMS}, and that
    BoundScopedOperations.java:53  return query.maxTimeMsec(timeout.toMillis());
    BoundScopedOperations.java:98  .maxTime(timeout)

  BoundScopedOperations.java:48    * <p>Mutates the caller's query rather than copying it, which is what Spring Data's own fluent
  BoundScopedOperations.java:49    * API does; a copy would silently drop any hint, collation or read preference the caller set.
  BoundScopedOperations.java:50    */
  BoundScopedOperations.java:51   private Query bounded(Query query) {
  BoundScopedOperations.java:52     Objects.requireNonNull(query, "query");
  BoundScopedOperations.java:53     return query.maxTimeMsec(timeout.toMillis());
  BoundScopedOperations.java:54   }
  BoundScopedOperations.java:55 
  BoundScopedOperations.java:56   @Override

  BoundScopedOperations.java:92 
  BoundScopedOperations.java:93   @Override
  BoundScopedOperations.java:94   public <T> List<T> aggregate(Aggregation aggregation, Class<T> resultType) {
  BoundScopedOperations.java:95     Aggregation bounded =
  BoundScopedOperations.java:96         aggregation.withOptions(
  BoundScopedOperations.java:97             org.springframework.data.mongodb.core.aggregation.AggregationOptions.builder()
  BoundScopedOperations.java:98                 .maxTime(timeout)
  BoundScopedOperations.java:99                 .build());
  BoundScopedOperations.java:100     return operations.aggregate(bounded, collection, resultType).getMappedResults();
  BoundScopedOperations.java:101   }
  BoundScopedOperations.java:102 }

# 그 타입에 닿는 유일한 문
  MongoCollectionAccess.java:24 
  MongoCollectionAccess.java:25   /**
  MongoCollectionAccess.java:26    * The operations this callback may perform.
  MongoCollectionAccess.java:27    *
  MongoCollectionAccess.java:28    * <p>Scoped: no method takes a collection name, so the check {@link #collection(String)} performs
  MongoCollectionAccess.java:29    * cannot be bypassed by not calling it. The previous {@code MongoOperations} accessor could reach
  MongoCollectionAccess.java:30    * any collection in the database.
  MongoCollectionAccess.java:31    */
  MongoCollectionAccess.java:32   ScopedMongoOperations scoped();
  MongoCollectionAccess.java:33 }

  MongoPlatformCollectionAccess.java:5 /**
  MongoPlatformCollectionAccess.java:6  * Raw access, for the platform's own executors only.
  MongoPlatformCollectionAccess.java:7  *
  MongoPlatformCollectionAccess.java:8  * <p>The bulk, atomic, aggregation and geospatial executors build driver-level commands and need
  MongoPlatformCollectionAccess.java:9  * the unrestricted template. They are inside the platform and are the code that installs the
  MongoPlatformCollectionAccess.java:10  * guardrails, which is a different position from a caller's callback — so the raw handle is a type
  MongoPlatformCollectionAccess.java:11  * they ask for by name rather than something every callback receives.
  MongoPlatformCollectionAccess.java:12  *
  MongoPlatformCollectionAccess.java:13  * <p>Keeping it out of {@link MongoCollectionAccess} is the point. An interface that offers both a
  MongoPlatformCollectionAccess.java:14  * scoped API and an escape hatch offers an escape hatch.
  MongoPlatformCollectionAccess.java:15  */
  MongoPlatformCollectionAccess.java:16 public interface MongoPlatformCollectionAccess extends MongoCollectionAccess {
  MongoPlatformCollectionAccess.java:17 
  MongoPlatformCollectionAccess.java:18   /** The template bound to the operation's consistency profile, with no collection scoping. */
  MongoPlatformCollectionAccess.java:19   MongoOperations rawOperations();
  MongoPlatformCollectionAccess.java:20 }

# 두 접근자를 부르는 자리 전수
  저장소 전체에서 scoped() 를 부르는 줄 : 0 개
  저장소 전체에서 rawOperations() 를 부르는 줄 : 7 개
  두 이름이 나오는 자리 전부 (선언 포함) :
    main · SpringMongoGeospatialOperations.java:58  return access.rawOperations().find(near, documentType, access.collection());
    main · SpringMongoGeospatialOperations.java:82  return access.rawOperations().find(within, documentType, access.collection());
    main · DefaultMongoImperativeExecutor.java:184  public ScopedMongoOperations scoped() {
    main · DefaultMongoImperativeExecutor.java:192  public MongoOperations rawOperations() {
    main · MongoCollectionAccess.java:32  ScopedMongoOperations scoped();
    main · MongoPlatformCollectionAccess.java:19  MongoOperations rawOperations();
    main · MongoAtomicOperationsTemplate.java:84  access.rawOperations(),
    main · MongoAtomicOperationsTemplate.java:92  access.rawOperations(),
    main · MongoBulkExecutor.java:69  access.rawOperations().bulkOps(plan.mode().toSpringMode(), access.collection());
    main · DefaultReactiveMongoExecutor.java:218  public ReactiveScopedMongoOperations scoped() {
    main · ReactiveMongoCollectionAccess.java:31  ReactiveScopedMongoOperations scoped();
    test · MongoRawAccessBoundaryTest.java:18  * <p>{@code MongoPlatformCollectionAccess.rawOperations()} and {@code
    test · MongoRawAccessBoundaryTest.java:37  List.of(".rawOperations()", ".executeInternal(");
  [대조] 그 검색이 훑은 파일 : 6444 개

# rawOperations 가 무엇을 돌려주는가
  DefaultMongoImperativeExecutor.java:180       return physicalCollection;
  DefaultMongoImperativeExecutor.java:181     }
  DefaultMongoImperativeExecutor.java:182 
  DefaultMongoImperativeExecutor.java:183     @Override
  DefaultMongoImperativeExecutor.java:184     public ScopedMongoOperations scoped() {
  DefaultMongoImperativeExecutor.java:185       // The deadline travels with the scope. The executor can only measure elapsed time after the
  DefaultMongoImperativeExecutor.java:186       // callback returns; the scoped operations send the same number to the server as maxTimeMS,
  DefaultMongoImperativeExecutor.java:187       // where it actually ends the work.
  DefaultMongoImperativeExecutor.java:188       return new BoundScopedOperations(physicalCollection, operations, timeout);
  DefaultMongoImperativeExecutor.java:189     }
  DefaultMongoImperativeExecutor.java:190 
  DefaultMongoImperativeExecutor.java:191     @Override
  DefaultMongoImperativeExecutor.java:192     public MongoOperations rawOperations() {
  DefaultMongoImperativeExecutor.java:193       return operations;
  DefaultMongoImperativeExecutor.java:194     }
  DefaultMongoImperativeExecutor.java:195   }
  DefaultMongoImperativeExecutor.java:196 }

# 서버에 데드라인을 실제로 붙이는 다른 경로들
  PolicyAwareMongoAggregationExecutor.java:88 
  PolicyAwareMongoAggregationExecutor.java:89   private static MongoOperationBudget budgetFor(
  PolicyAwareMongoAggregationExecutor.java:90       MongoOperationContext context, MongoOperationBudget registered) {
  PolicyAwareMongoAggregationExecutor.java:91     // The context's timeout is the caller's deadline; it may tighten maxTimeMS but never extend it.
  PolicyAwareMongoAggregationExecutor.java:92     long contextMillis = Math.max(1L, context.timeout().toMillis());
  PolicyAwareMongoAggregationExecutor.java:93     return new MongoOperationBudget(
  PolicyAwareMongoAggregationExecutor.java:94         registered.maxResults(),
  PolicyAwareMongoAggregationExecutor.java:95         registered.maxResultBytes(),
  PolicyAwareMongoAggregationExecutor.java:96         Math.min(registered.maxTimeMillis(), contextMillis),
  PolicyAwareMongoAggregationExecutor.java:97         registered.cursorBatchSize());
  PolicyAwareMongoAggregationExecutor.java:98   }
  PolicyAwareMongoAggregationExecutor.java:99 
  PolicyAwareMongoAggregationExecutor.java:100   private static AggregationOptions optionsFor(
  PolicyAwareMongoAggregationExecutor.java:101       MongoAggregationProfile profile, MongoOperationBudget budget) {
  PolicyAwareMongoAggregationExecutor.java:102     AggregationOptions.Builder options =
  PolicyAwareMongoAggregationExecutor.java:103         AggregationOptions.builder()
  PolicyAwareMongoAggregationExecutor.java:104             .allowDiskUse(profile.allowDiskUse())
  PolicyAwareMongoAggregationExecutor.java:105             .cursorBatchSize(budget.cursorBatchSize())
  PolicyAwareMongoAggregationExecutor.java:106             .maxTime(Duration.ofMillis(budget.maxTimeMillis()));
  PolicyAwareMongoAggregationExecutor.java:107     return profile.strictMapping() ? options.strictMapping().build() : options.build();
  PolicyAwareMongoAggregationExecutor.java:108   }
  maxTimeMillis 를 부르는 자리 전부 (에러 메시지 포함) :
    PolicyAwareMongoAggregationExecutor.java:96  Math.min(registered.maxTimeMillis(), contextMillis),
    PolicyAwareMongoAggregationExecutor.java:106  .maxTime(Duration.ofMillis(budget.maxTimeMillis()));
    PolicyAwareMongoQueryBuilder.java:200  query.maxTimeMsec(budget.maxTimeMillis());
    MongoBudgetEnforcer.java:36  + requested.maxTimeMillis()
    MongoBudgetEnforcer.java:44  + registered.maxTimeMillis()
    MongoReactiveCursorPublisher.java:58  .maxTimeMsec(budget.maxTimeMillis())
  context.timeout() 이나 narrowedTo 가 나오는 자리 전부 :
    PolicyAwareMongoAggregationExecutor.java:72  enforcer.narrow(budget, budget.narrowedTo(budgetFor(context, budget)));
    PolicyAwareMongoAggregationExecutor.java:92  long contextMillis = Math.max(1L, context.timeout().toMillis());
    DefaultMongoImperativeExecutor.java:83  ScopedAccess access = new ScopedAccess(physicalCollection, operations, context.timeout());
    DefaultMongoImperativeExecutor.java:93  if (elapsed.compareTo(context.timeout()) > 0) {
    DefaultMongoImperativeExecutor.java:103  + context.timeout().toMillis()
    MongoBudgetEnforcer.java:57  return registered.narrowedTo(requested);
    MongoOperationBudget.java:43  public MongoOperationBudget narrowedTo(MongoOperationBudget other) {
    DefaultReactiveMongoExecutor.java:76  .timeout(context.timeout())
    DefaultReactiveMongoExecutor.java:108  .timeout(context.timeout())
    DefaultReactiveMongoExecutor.java:154  context.operationName(), operationType, context.timeout()),

# 그 다섯 자리를 가진 세 실행기가 조립되는가
    MongoPlatformAutoConfiguration.java:154  .MongoAtomicOperationsTemplate(executor, policies);
    MongoPlatformAutoConfiguration.java:169  return new dev.caskeleton.adapter.outbound.mongo.imperative.bulk.MongoBulkExecutor(
    SpringMongoGeospatialOperations.java:31  public SpringMongoGeospatialOperations(
    MongoAtomicOperationsTemplate.java:27  public MongoAtomicOperationsTemplate(
    MongoBulkExecutor.java:43  public MongoBulkExecutor(
  그 셋이 자기 안에서 데드라인을 따로 거는가 :
    SpringMongoGeospatialOperations.java maxTime 이나 timeout 이 나오는 줄 : 0 개
    MongoAtomicOperationsTemplate.java maxTime 이나 timeout 이 나오는 줄 : 0 개
    MongoBulkExecutor.java             maxTime 이나 timeout 이 나오는 줄 : 0 개
    [대조] 같은 검색을 BoundScopedOperations 에 걸면 : 8 줄

# 저장소가 그 손잡이를 어떻게 지키는가
  MongoRawAccessBoundaryTest.java:15 /**
  MongoRawAccessBoundaryTest.java:16  * The Mongo platform's raw escape hatches stay inside the platform.
  MongoRawAccessBoundaryTest.java:17  *
  MongoRawAccessBoundaryTest.java:18  * <p>{@code MongoPlatformCollectionAccess.rawOperations()} and {@code
  MongoRawAccessBoundaryTest.java:19  * DefaultMongoImperativeExecutor.executeInternal(...)} hand out Spring Data's unbounded {@code
  MongoRawAccessBoundaryTest.java:20  * MongoOperations} — no collection binding, no consistency template, no deadline, no result budget.
  MongoRawAccessBoundaryTest.java:21  * The scoped API exists precisely so a caller cannot reach those, and the only thing stopping one
  MongoRawAccessBoundaryTest.java:22  * was a javadoc sentence saying "not public API for callers".
  MongoRawAccessBoundaryTest.java:23  *
  MongoRawAccessBoundaryTest.java:24  * <p>Both are genuinely needed *inside* the platform: the geospatial, atomic and bulk operations
  MongoRawAccessBoundaryTest.java:25  * are built on them. So the rule is not "delete them" but "nobody outside may call them", which is
  MongoRawAccessBoundaryTest.java:26  * a boundary rather than a visibility problem — the callers live in sibling packages, so Java's
  MongoRawAccessBoundaryTest.java:27  * package-private cannot express it.
  MongoRawAccessBoundaryTest.java:28  *
  MongoRawAccessBoundaryTest.java:29  * <p>Checked from the composition root because that is the only place that sees both the platform
  MongoRawAccessBoundaryTest.java:30  * and everything that consumes it. A rule living inside the Mongo leaf could only ever prove the
  MongoRawAccessBoundaryTest.java:31  * leaf does not violate itself.
  MongoRawAccessBoundaryTest.java:32  */
  MongoRawAccessBoundaryTest.java:35   /** The escape hatches, by the text a caller would have to write to use one. */
  MongoRawAccessBoundaryTest.java:36   private static final List<String> ESCAPE_HATCHES =
  MongoRawAccessBoundaryTest.java:37       List.of(".rawOperations()", ".executeInternal(");
  MongoRawAccessBoundaryTest.java:38 
  MongoRawAccessBoundaryTest.java:39   /** Where they may be used: the Mongo adapter's own production sources. */
  MongoRawAccessBoundaryTest.java:40   private static final String PLATFORM_SOURCE =
  MongoRawAccessBoundaryTest.java:41       "/src/adapter/outbound/persistence-mongo/src/main/java/";

# 세 실행기가 대신 하는 것
  DefaultMongoImperativeExecutor.java:85     long startedAt = System.nanoTime();
  DefaultMongoImperativeExecutor.java:86     try (MongoOperationObservation observation = observer.start(context, operationType)) {
  DefaultMongoImperativeExecutor.java:87       try {
  DefaultMongoImperativeExecutor.java:88         T value = callback.doInMongo(access);
  DefaultMongoImperativeExecutor.java:89         Duration elapsed = Duration.ofNanos(System.nanoTime() - startedAt);
  DefaultMongoImperativeExecutor.java:90         // A read is not a confirmed write. Recording every successful FIND as WRITE_CONFIRMED made
  DefaultMongoImperativeExecutor.java:91         // the metric that answers "are writes being acknowledged" count reads as well.
  DefaultMongoImperativeExecutor.java:92         MongoExecutionOutcome outcome = MongoCompletion.successOutcomeFor(operationType);
  DefaultMongoImperativeExecutor.java:93         if (elapsed.compareTo(context.timeout()) > 0) {
  DefaultMongoImperativeExecutor.java:94           // The context declares a deadline on every operation and nothing compared anything to it.
  DefaultMongoImperativeExecutor.java:95           // A callback cannot be interrupted mid-driver-call, so this cannot cut the work short —
  DefaultMongoImperativeExecutor.java:96           // but reporting a breach beats reporting success for work that ran past its budget.
  DefaultMongoImperativeExecutor.java:97           observation.success(outcome);
  DefaultMongoImperativeExecutor.java:98           throw MongoOperationRejectedException.of(
  DefaultMongoImperativeExecutor.java:99               context.operationName().value(),
  DefaultMongoImperativeExecutor.java:100               "the operation ran for "
  DefaultMongoImperativeExecutor.java:101                   + elapsed.toMillis()
  DefaultMongoImperativeExecutor.java:102                   + "ms against a declared timeout of "
  DefaultMongoImperativeExecutor.java:103                   + context.timeout().toMillis()
  DefaultMongoImperativeExecutor.java:104                   + "ms");
  DefaultMongoImperativeExecutor.java:105         }
  DefaultMongoImperativeExecutor.java:106         observation.success(outcome);
