docs: private void scanDirectory(final File directory, final String relativePath, final ScanContext scanContext) {
          final List<File> children = listDirectoryChildren(directory, filter);
          for (File child : children) {
              final String fileName = child.getName();
              if (fileName.endsWith(DEPLOYED)) {
                  final String deploymentName = fileName.substring(0, fileName.length() - DEPLOYED.length());
                  DeploymentMarker deploymentMarker = deployed.get(deploymentName);
                  if (deploymentMarker == null) {
                      scanContext.toRemove.remove(deploymentName);
                      removeExtraneousMarker(child, fileName);
                  } else {
                      final File deploymentFile = new File(directory, deploymentName);
                      if (deploymentFile.exists()) {
                          scanContext.toRemove.remove(deploymentName);
                          if (deployed.get(deploymentName).lastModified != child.lastModified()) {
                              scanContext.scannerTasks.add(new RedeployTask(deploymentName, child.lastModified(), directory,
                                      !child.isDirectory()));
                          } else {
                              // AS7-784 check for undeploy or removal of the deployment via another management client
                              Boolean isDeployed = scanContext.registeredDeployments.get(deploymentName);
                              if (isDeployed == null || !isDeployed) {
                                  // It was undeployed or removed; get rid of the .deployed marker and
                                  // put down a .undeployed marker so we don't process this again
                                  deployed.remove(deploymentName);
                                  removeExtraneousMarker(child, fileName);
                                  final File marker = new File(directory, deploymentName + UNDEPLOYED);
                                  createMarkerFile(marker, deploymentName);
                                  if (isDeployed == null) {
                                      DeploymentScannerLogger.ROOT_LOGGER.scannerDeploymentRemovedButNotByScanner(deploymentName, marker);
                                  } else {
                                      DeploymentScannerLogger.ROOT_LOGGER.scannerDeploymentUndeployedButNotByScanner(deploymentName, marker);
                                  }
                              }
                          }
                      } else {
                          boolean autoDeployable = deploymentMarker.archive ? autoDeployZip : autoDeployExploded;
                          if (!autoDeployable) {
                              // Don't undeploy but log a warn if this is exploded content
                              scanContext.toRemove.remove(deploymentName);
                              if (!deploymentMarker.archive) {
                                  scanContext.prematureExplodedDeletions.add(deploymentName);
                              }
                          }
                          // else AS7-1240 -- content is gone, leave deploymentName in scanContext.toRemove to trigger undeploy
                      }
                  }
              } else if (fileName.endsWith(DO_DEPLOY) || (fileName.endsWith(FAILED_DEPLOY) && firstScan)) {
                  // AS7-2581 - attempt to redeploy failed deployments on restart.
                  final String markerStatus = fileName.endsWith(DO_DEPLOY) ? DO_DEPLOY : FAILED_DEPLOY;
                  final String deploymentName = fileName.substring(0, fileName.length() - markerStatus.length());
  
                  if (FAILED_DEPLOY.equals(markerStatus)) {
                      if (!scanContext.firstScanDeployments.add(deploymentName)) {
                          continue;
                      }
                      ROOT_LOGGER.reattemptingFailedDeployment(deploymentName);
                  }
  
                  final File deploymentFile = new File(directory, deploymentName);
                  if (!deploymentFile.exists()) {
                      scanContext.ignoredMissingDeployments.add(deploymentName);
                      continue;
                  }
                  long timestamp = getDeploymentTimestamp(deploymentFile);
                  final String path = relativeTo == null ? deploymentFile.getAbsolutePath() : relativePath + deploymentName; // TODO:
                  // sub-directories
                  // in
                  // the
                  // deploymentDir
                  final boolean archive = deploymentFile.isFile();
                  addContentAddingTask(path, archive, deploymentName, deploymentFile, timestamp, scanContext);
              } else if (fileName.endsWith(FAILED_DEPLOY)) {
                  final String deploymentName = fileName.substring(0, fileName.length() - FAILED_DEPLOY.length());
                  scanContext.toRemove.remove(deploymentName);
                  if (!deployed.containsKey(deploymentName) && !(new File(child.getParent(), deploymentName).exists())) {
                      removeExtraneousMarker(child, fileName);
                  }
              } else if (isEEArchive(fileName)) {
                  boolean autoDeployable = child.isDirectory() ? autoDeployExploded : autoDeployZip;
                  if (autoDeployable) {
                      if (!isAutoDeployDisabled(child)) {
                          long timestamp = getDeploymentTimestamp(child);
                          synchronizeScannerStatus(scanContext, directory, fileName, timestamp);
                          if (isFailedOrUndeployed(scanContext, directory, fileName, timestamp) || scanContext.firstScanDeployments.contains(fileName)) {
                              continue;
                          }
  
                          DeploymentMarker marker = deployed.get(fileName);
                          if (marker == null || marker.lastModified != timestamp) {
                              try {
                                  if (isZipComplete(child)) {
                                      final String path = relativeTo == null ? child.getAbsolutePath() : relativePath + fileName;
                                      final boolean archive = child.isFile();
                                      if(firstScan){
                                          scanContext.firstScanDeployments.add(fileName);
                                      }
                                      addContentAddingTask(path, archive, fileName, child, timestamp, scanContext);
                                  } else {
                                      //we need to make sure that the file was not deleted while
                                      //the scanner was running
                                      if (child.exists()) {
                                          scanContext.incompleteFiles.put(child, new IncompleteDeploymentStatus(child, timestamp));
                                      }
                                  }
                              } catch (NonScannableZipException e) {
                                  // Track for possible logging in scan()
                                  scanContext.nonscannable.put(child, new NonScannableStatus(e, timestamp));
                              }
                          }
                      }
                  } else if (!deployed.containsKey(fileName) && !new File(fileName + DO_DEPLOY).exists()
                          && !new File(fileName + FAILED_DEPLOY).exists()) {
                      // Track for possible INFO logging of the need for a marker
                      scanContext.nonDeployable.add(fileName);
                  }
              } else if (isXmlFile(fileName)) {
                  if (autoDeployXml) {
                      if (!isAutoDeployDisabled(child)) {
                          long timestamp = getDeploymentTimestamp(child);
                          if (isFailedOrUndeployed(scanContext, directory, fileName, timestamp) || scanContext.firstScanDeployments.contains(fileName)) {
                              continue;
                          }
  
                          DeploymentMarker marker = deployed.get(fileName);
                          if (marker == null || marker.lastModified != timestamp) {
                              if (isXmlComplete(child)) {
                                  final String path = relativeTo == null ? child.getAbsolutePath() : relativePath + fileName;
                                  if(firstScan){
                                      scanContext.firstScanDeployments.add(fileName);
                                  }
                                  addContentAddingTask(path, true, fileName, child, timestamp, scanContext);
                              } else {
                                  //we need to make sure that the file was not deleted while
                                  //the scanner was running
                                  if (child.exists()) {
                                      scanContext.incompleteFiles.put(child, new IncompleteDeploymentStatus(child, timestamp));
                                  }
                              }
                          }
                      }
                  } else if (!deployed.containsKey(fileName) && !new File(fileName + DO_DEPLOY).exists()
                          && !new File(fileName + FAILED_DEPLOY).exists()) {
                      // Track for possible INFO logging of the need for a marker
                      scanContext.nonDeployable.add(fileName);
                  }
              } else if (fileName.endsWith(DEPLOYING) || fileName.endsWith(UNDEPLOYING)) {
                  // These markers should not survive a scan
                  removeExtraneousMarker(child, fileName);
              } else if (fileName.endsWith(PENDING)) {
                  // Do some housekeeping if the referenced deployment is gone
                  final String deploymentName = fileName.substring(0, fileName.length() - PENDING.length());
                  File deployment = new File(child.getParent(), deploymentName);
                  if (!deployment.exists()) {
                      removeExtraneousMarker(child, fileName);
                  }
              } else if (child.isDirectory()) { // exploded deployments would have been caught by isEEArchive(fileName) above
  
                  if (WEB_INF.equalsIgnoreCase(fileName) || META_INF.equalsIgnoreCase(fileName)) {
                      // Looks like someone unzipped an archive in the scanned dir
                      // Track for possible ERROR logging
                      scanContext.illegalDir.add(fileName);
                  } else {
                      scanDirectory(child, relativePath + child.getName() + File.separator, scanContext);
                  }
              }
          }
      }