docs: private ShardSpecs determineShardSpecs(
        final TaskToolbox toolbox,
        final FirehoseFactory firehoseFactory,
        final File firehoseTempDir,
        @Nullable final Integer maxRowsPerSegment
    ) throws IOException
    {
      final ObjectMapper jsonMapper = toolbox.getObjectMapper();
      final IndexTuningConfig tuningConfig = ingestionSchema.getTuningConfig();
      final IndexIOConfig ioConfig = ingestionSchema.getIOConfig();
  
      final GranularitySpec granularitySpec = ingestionSchema.getDataSchema().getGranularitySpec();
  
      // Must determine intervals if unknown, since we acquire all locks before processing any data.
      final boolean determineIntervals = !granularitySpec.bucketIntervals().isPresent();
  
      // Must determine partitions if rollup is guaranteed and the user didn't provide a specific value.
      final boolean determineNumPartitions = tuningConfig.getNumShards() == null
                                             && isGuaranteedRollup(ioConfig, tuningConfig);
  
      // if we were given number of shards per interval and the intervals, we don't need to scan the data
      if (!determineNumPartitions && !determineIntervals) {
        log.info("Skipping determine partition scan");
        return createShardSpecWithoutInputScan(
            jsonMapper,
            granularitySpec,
            ioConfig,
            tuningConfig
        );
      } else {
        // determine intervals containing data and prime HLL collectors
        return createShardSpecsFromInput(
            jsonMapper,
            ingestionSchema,
            firehoseFactory,
            firehoseTempDir,
            granularitySpec,
            tuningConfig,
            determineIntervals,
            determineNumPartitions,
            maxRowsPerSegment
        );
      }
    }