Class ScanOrchestrator
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:
- Load all configured
TestDiscoveryproviders. - For each scan root, run every provider, merge their results, and group methods by class.
- For each class, optionally consult the AI engine through a layered cache + override lookup.
- Forward each method record to the supplied sink.
- 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:
scan(java.util.List<java.nio.file.Path>, org.egothor.methodatlas.CliConfig, org.egothor.methodatlas.api.TestDiscoveryConfig, org.egothor.methodatlas.ai.AiSuggestionEngine, org.egothor.methodatlas.emit.TestMethodSink, org.egothor.methodatlas.emit.ClassificationOverride, org.egothor.methodatlas.AiResultCache)manages the provider lifecycle internally; it is the right call for SARIF, JSON, and GitHub-annotation modes that buffer or emit unconditionally.runDiscovery(java.nio.file.Path, java.util.List<org.egothor.methodatlas.api.TestDiscovery>, org.egothor.methodatlas.ai.AiOptions, org.egothor.methodatlas.ai.AiSuggestionEngine, org.egothor.methodatlas.emit.TestMethodSink, boolean, org.egothor.methodatlas.emit.ClassificationOverride, org.egothor.methodatlas.AiResultCache)processes a single root against pre-loaded providers; it is the right call for CSV and plain-text modes that compute per-root metadata (such as thesource_rootcolumn) before forwarding records.
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
ConstructorsConstructorDescriptionScanOrchestrator(PluginLoader pluginLoader) Creates a new orchestrator that will resolve providers throughpluginLoader. -
Method Summary
Modifier and TypeMethodDescriptioncollectMethodsByFile(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.TestMethodSinkfilterSink(org.egothor.methodatlas.emit.TestMethodSink delegate, boolean securityOnly, double minConfidence, boolean confidenceEnabled) Wraps aTestMethodSinkso that only records that pass all active filters are forwarded todelegate.voidgatherAiSuggestionsForFile(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 inbyClassand populatestagsToApplyanddisplayNameswith the results for methods that are security-relevant.booleanrunDiscovery(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 configuredTestDiscoveryproviders onroot, merges their results, orchestrates AI analysis per class, and forwards each method record tosink.intscan(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 tosink.static org.egothor.methodatlas.ai.PromptBuilder.TargetMethodtoTargetMethod(org.egothor.methodatlas.api.DiscoveredMethod m) Converts a single discovered test method into a prompt target descriptor.
-
Constructor Details
-
ScanOrchestrator
Creates a new orchestrator that will resolve providers throughpluginLoader.- Parameters:
pluginLoader- plugin loader used byscan(java.util.List<java.nio.file.Path>, org.egothor.methodatlas.CliConfig, org.egothor.methodatlas.api.TestDiscoveryConfig, org.egothor.methodatlas.ai.AiSuggestionEngine, org.egothor.methodatlas.emit.TestMethodSink, org.egothor.methodatlas.emit.ClassificationOverride, org.egothor.methodatlas.AiResultCache)andcollectMethodsByFile(java.util.List<java.nio.file.Path>, java.util.List<org.egothor.methodatlas.api.TestDiscovery>); must not benull
-
-
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 tosink. Loads and closes theTestDiscoveryproviders internally so callers do not need to manage the lifecycle.- Parameters:
roots- source roots to scan; must not benullcliConfig- full parsed CLI configurationdiscoveryConfig- discovery configuration forwarded to providersaiEngine- AI engine providing suggestions; may benullwhen AI is disabledsink- receiver of discovered test method recordsoverride- human classification overridesaiCache- AI result cache- Returns:
0if all files were processed successfully,1if 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 configuredTestDiscoveryproviders onroot, merges their results, orchestrates AI analysis per class, and forwards each method record tosink.Providers are passed in pre-loaded; callers manage the lifecycle (typically through
PluginLoader.closeAll(List)in afinallyblock) so that they can share one provider list across multiple roots while still computing per-root metadata before each call.- Parameters:
root- directory to scanproviders- list of pre-configured discovery providersaiOptions- AI configuration for the current runaiEngine- AI engine, ornullwhen AI is disabledsink- receiver of discovered test method recordscontentHashEnabled- whether to include the class content hash in emitted recordsoverride- human classification overridesaiCache- AI result cache- Returns:
trueif 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 whoseDiscoveredMethod.filePath()isnullare 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 benullproviders- configured and already-loaded discovery providers; must not benull- 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 inbyClassand populatestagsToApplyanddisplayNameswith the results for methods that are security-relevant.A display-name suggestion is only placed into
displayNameswhen the discovered method has no existing@DisplayNamein source (i.e.DiscoveredMethod.displayName()returnsnull). This prevents AI-generated names from overwriting manually authored ones.- Parameters:
byClass- discovered methods grouped by FQCN for one source fileai- AI runtime carrying the engine, override, and cacheaiCache- AI result cache used to compute the content-hash lookup keytagsToApply- output accumulator: method name to tag values to writedisplayNames- 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 aTestMethodSinkso that only records that pass all active filters are forwarded todelegate.Two independent filters are supported and composed in order:
- Security-only filter — when
securityOnlyistrue, records whoseAiMethodSuggestionisnullor hassecurityRelevant=falseare dropped. - Confidence threshold filter — when
confidenceEnabledistrueandminConfidence > 0.0, records whoseAiMethodSuggestionisnullor has aAiMethodSuggestion.confidence()belowminConfidenceare dropped. This filter is a no-op whenconfidenceEnabledisfalsebecause the confidence field is always0.0when confidence scoring was not requested.
When neither filter is active the original
delegateis returned unchanged (zero overhead).- Parameters:
delegate- the underlying sink to forward matching records tosecurityOnly- whether to enable the security-relevance filterminConfidence- minimum confidence score (inclusive) required to pass the confidence filter;0.0disables itconfidenceEnabled- whether confidence scoring was requested; must betruefor the confidence filter to activate- Returns:
- filtered sink, or
delegateunchanged when all filters are off
- Security-only filter — when
-
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
ManualPrepareCommandalso 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 benull- Returns:
- corresponding prompt target descriptor; never
null - See Also:
-