Class ScanOrchestrator

java.lang.Object
org.egothor.methodatlas.command.ScanOrchestrator

public final class ScanOrchestrator extends Object
Orchestrates the scan-and-emit loop that every command mode is built around.

Each Command mode varies in three places — output format, per-record sink behaviour, and whether records stream or buffer — but they all share the same core sequence:

  1. Load all configured TestDiscovery providers.
  2. For each scan root, run every provider, merge their results, and group methods by class.
  3. For each class, optionally consult the AI engine through a layered cache + override lookup.
  4. Forward each method record to the supplied sink.
  5. Close all providers.

This class owns that sequence. Commands compose it with a PluginLoader (passed in at construction) and configure the per-record sink, AI runtime, and content-hash policy at call time.

API shape

Two entry points serve the two common patterns:

The apply-tags flow has its own shape: collectMethodsByFile(java.util.List<java.nio.file.Path>, java.util.List<org.egothor.methodatlas.api.TestDiscovery>) groups discovered methods by source file (the caller owns the provider lifecycle so it can read each provider's TestDiscovery.hadErrors() afterwards), and gatherAiSuggestionsForFile(java.util.Map<java.lang.String, java.util.List<org.egothor.methodatlas.api.DiscoveredMethod>>, org.egothor.methodatlas.command.AiRuntime, org.egothor.methodatlas.AiResultCache, java.util.Map<java.lang.String, java.util.List<java.lang.String>>, java.util.Map<java.lang.String, java.lang.String>) resolves AI suggestions for one file at a time.

Thread safety

This class is thread-safe. The injected PluginLoader is thread-safe and ServiceLoader resolution is idempotent; nothing else is shared between calls.

Since:
1.0.0
See Also:
  • Constructor Summary

    Constructors
    Constructor
    Description
    Creates a new orchestrator that will resolve providers through pluginLoader.
  • Method Summary

    Modifier and Type
    Method
    Description
    Map<Path,List<org.egothor.methodatlas.api.DiscoveredMethod>>
    collectMethodsByFile(List<Path> roots, List<org.egothor.methodatlas.api.TestDiscovery> providers)
    Collects all discovered methods from every configured root, keyed by source-file path.
    org.egothor.methodatlas.emit.TestMethodSink
    filterSink(org.egothor.methodatlas.emit.TestMethodSink delegate, boolean securityOnly, double minConfidence, boolean confidenceEnabled)
    Wraps a TestMethodSink so that only records that pass all active filters are forwarded to delegate.
    void
    gatherAiSuggestionsForFile(Map<String,List<org.egothor.methodatlas.api.DiscoveredMethod>> byClass, AiRuntime ai, AiResultCache aiCache, Map<String,List<String>> tagsToApply, Map<String,String> displayNames)
    Resolves AI security-classification suggestions for every class in byClass and populates tagsToApply and displayNames with the results for methods that are security-relevant.
    boolean
    runDiscovery(Path root, List<org.egothor.methodatlas.api.TestDiscovery> providers, org.egothor.methodatlas.ai.AiOptions aiOptions, org.egothor.methodatlas.ai.AiSuggestionEngine aiEngine, org.egothor.methodatlas.emit.TestMethodSink sink, boolean contentHashEnabled, org.egothor.methodatlas.emit.ClassificationOverride override, AiResultCache aiCache)
    Runs all configured TestDiscovery providers on root, merges their results, orchestrates AI analysis per class, and forwards each method record to sink.
    int
    scan(List<Path> roots, CliConfig cliConfig, org.egothor.methodatlas.api.TestDiscoveryConfig discoveryConfig, org.egothor.methodatlas.ai.AiSuggestionEngine aiEngine, org.egothor.methodatlas.emit.TestMethodSink sink, org.egothor.methodatlas.emit.ClassificationOverride override, AiResultCache aiCache)
    Scans every configured root, forwarding each discovered test method to sink.
    static org.egothor.methodatlas.ai.PromptBuilder.TargetMethod
    toTargetMethod(org.egothor.methodatlas.api.DiscoveredMethod m)
    Converts a single discovered test method into a prompt target descriptor.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

  • Method Details

    • scan

      public int scan(List<Path> roots, CliConfig cliConfig, org.egothor.methodatlas.api.TestDiscoveryConfig discoveryConfig, org.egothor.methodatlas.ai.AiSuggestionEngine aiEngine, org.egothor.methodatlas.emit.TestMethodSink sink, org.egothor.methodatlas.emit.ClassificationOverride override, AiResultCache aiCache) throws IOException
      Scans every configured root, forwarding each discovered test method to sink. Loads and closes the TestDiscovery providers internally so callers do not need to manage the lifecycle.
      Parameters:
      roots - source roots to scan; must not be null
      cliConfig - full parsed CLI configuration
      discoveryConfig - discovery configuration forwarded to providers
      aiEngine - AI engine providing suggestions; may be null when AI is disabled
      sink - receiver of discovered test method records
      override - human classification overrides
      aiCache - AI result cache
      Returns:
      0 if all files were processed successfully, 1 if any file produced a parse or processing error
      Throws:
      IOException - if traversing a file tree fails
    • runDiscovery

      public boolean runDiscovery(Path root, List<org.egothor.methodatlas.api.TestDiscovery> providers, org.egothor.methodatlas.ai.AiOptions aiOptions, org.egothor.methodatlas.ai.AiSuggestionEngine aiEngine, org.egothor.methodatlas.emit.TestMethodSink sink, boolean contentHashEnabled, org.egothor.methodatlas.emit.ClassificationOverride override, AiResultCache aiCache) throws IOException
      Runs all configured TestDiscovery providers on root, merges their results, orchestrates AI analysis per class, and forwards each method record to sink.

      Providers are passed in pre-loaded; callers manage the lifecycle (typically through PluginLoader.closeAll(List) in a finally block) so that they can share one provider list across multiple roots while still computing per-root metadata before each call.

      Parameters:
      root - directory to scan
      providers - list of pre-configured discovery providers
      aiOptions - AI configuration for the current run
      aiEngine - AI engine, or null when AI is disabled
      sink - receiver of discovered test method records
      contentHashEnabled - whether to include the class content hash in emitted records
      override - human classification overrides
      aiCache - AI result cache
      Returns:
      true if any provider encountered a parse or processing error
      Throws:
      IOException - if traversing the file tree fails
    • collectMethodsByFile

      public Map<Path,List<org.egothor.methodatlas.api.DiscoveredMethod>> collectMethodsByFile(List<Path> roots, List<org.egothor.methodatlas.api.TestDiscovery> providers) throws IOException
      Collects all discovered methods from every configured root, keyed by source-file path. Methods whose DiscoveredMethod.filePath() is null are silently skipped.

      Providers are passed in pre-loaded so the caller can read each provider's TestDiscovery.hadErrors() after the call and decide how to propagate the exit code; the caller also owns closing them.

      Parameters:
      roots - scan roots; must not be null
      providers - configured and already-loaded discovery providers; must not be null
      Returns:
      mutable map from source-file path to the methods found in that file; insertion order matches discovery order
      Throws:
      IOException - if directory traversal fails for any root
    • gatherAiSuggestionsForFile

      public void gatherAiSuggestionsForFile(Map<String,List<org.egothor.methodatlas.api.DiscoveredMethod>> byClass, AiRuntime ai, AiResultCache aiCache, Map<String,List<String>> tagsToApply, Map<String,String> displayNames)
      Resolves AI security-classification suggestions for every class in byClass and populates tagsToApply and displayNames with the results for methods that are security-relevant.

      A display-name suggestion is only placed into displayNames when the discovered method has no existing @DisplayName in source (i.e. DiscoveredMethod.displayName() returns null). This prevents AI-generated names from overwriting manually authored ones.

      Parameters:
      byClass - discovered methods grouped by FQCN for one source file
      ai - AI runtime carrying the engine, override, and cache
      aiCache - AI result cache used to compute the content-hash lookup key
      tagsToApply - output accumulator: method name to tag values to write
      displayNames - output accumulator: method name to display name to write
    • filterSink

      public org.egothor.methodatlas.emit.TestMethodSink filterSink(org.egothor.methodatlas.emit.TestMethodSink delegate, boolean securityOnly, double minConfidence, boolean confidenceEnabled)
      Wraps a TestMethodSink so that only records that pass all active filters are forwarded to delegate.

      Two independent filters are supported and composed in order:

      1. Security-only filter — when securityOnly is true, records whose AiMethodSuggestion is null or has securityRelevant=false are dropped.
      2. Confidence threshold filter — when confidenceEnabled is true and minConfidence > 0.0, records whose AiMethodSuggestion is null or has a AiMethodSuggestion.confidence() below minConfidence are dropped. This filter is a no-op when confidenceEnabled is false because the confidence field is always 0.0 when confidence scoring was not requested.

      When neither filter is active the original delegate is returned unchanged (zero overhead).

      Parameters:
      delegate - the underlying sink to forward matching records to
      securityOnly - whether to enable the security-relevance filter
      minConfidence - minimum confidence score (inclusive) required to pass the confidence filter; 0.0 disables it
      confidenceEnabled - whether confidence scoring was requested; must be true for the confidence filter to activate
      Returns:
      filtered sink, or delegate unchanged when all filters are off
    • toTargetMethod

      public static org.egothor.methodatlas.ai.PromptBuilder.TargetMethod toTargetMethod(org.egothor.methodatlas.api.DiscoveredMethod m)
      Converts a single discovered test method into a prompt target descriptor.

      Exposed publicly because ManualPrepareCommand also needs to build prompt-target lists from discovered methods when writing manual work files; the conversion logic must stay aligned across both call sites to keep the prompt format consistent.

      Parameters:
      m - discovered test method; must not be null
      Returns:
      corresponding prompt target descriptor; never null
      See Also:
      • PromptBuilder.TargetMethod