AnalyzeRequirementUseCase.java
package com.taxonomy.analysis.usecase;
import com.taxonomy.analysis.service.AiPromptBudgetPolicy;
import com.taxonomy.analysis.service.AnalysisRelationGenerator;
import com.taxonomy.analysis.service.LlmProvider;
import com.taxonomy.analysis.service.LlmService;
import com.taxonomy.architecture.service.RequirementArchitectureViewService;
import com.taxonomy.dto.AnalysisResult;
import com.taxonomy.dto.RequirementArchitectureView;
import com.taxonomy.export.DiagramViewMetadata;
import com.taxonomy.preferences.PreferencesService;
import com.taxonomy.shared.config.ExportConfig;
import com.taxonomy.versioning.service.HypothesisService;
import com.taxonomy.versioning.service.RepositoryStateService;
import org.springframework.stereotype.Service;
import java.util.Locale;
@Service
public class AnalyzeRequirementUseCase {
private final LlmService llmService;
private final AiPromptBudgetPolicy promptBudgetPolicy;
private final RequirementArchitectureViewService architectureViewService;
private final AnalysisRelationGenerator analysisRelationGenerator;
private final HypothesisService hypothesisService;
private final RepositoryStateService repositoryStateService;
private final PreferencesService preferencesService;
public AnalyzeRequirementUseCase(
LlmService llmService,
AiPromptBudgetPolicy promptBudgetPolicy,
RequirementArchitectureViewService architectureViewService,
AnalysisRelationGenerator analysisRelationGenerator,
HypothesisService hypothesisService,
RepositoryStateService repositoryStateService,
PreferencesService preferencesService) {
this.llmService = llmService;
this.promptBudgetPolicy = promptBudgetPolicy;
this.architectureViewService = architectureViewService;
this.analysisRelationGenerator = analysisRelationGenerator;
this.hypothesisService = hypothesisService;
this.repositoryStateService = repositoryStateService;
this.preferencesService = preferencesService;
}
/**
* Analyze a request. Ad-hoc requests persist generated hypotheses immediately.
* Project analyses carry immutable snapshot provenance; their caller owns a
* durable claim boundary and therefore persists hypotheses only after that
* claim has been revalidated and locked.
*/
public AnalyzeRequirementResult analyze(AnalyzeRequirementCommand command) {
return analyze(command, command.provenance() == null);
}
private AnalyzeRequirementResult analyze(AnalyzeRequirementCommand command,
boolean persistHypotheses) {
try {
applyProviderOverride(command.provider());
promptBudgetPolicy.requireWithinBudget(
command.businessText(), command.provider());
AnalysisResult result = llmService.analyzeWithBudget(command.businessText());
enrichWithRelationHypotheses(command, result, persistHypotheses);
enrichWithArchitectureView(command, result);
populateViewContext(command, result);
return new AnalyzeRequirementResult(result);
} finally {
llmService.clearRequestProvider();
}
}
private void applyProviderOverride(String provider) {
if (provider == null || provider.isBlank()
|| "MOCK".equalsIgnoreCase(provider)) {
return;
}
try {
llmService.setRequestProvider(LlmProvider.valueOf(provider.toUpperCase(Locale.ROOT)));
} catch (IllegalArgumentException e) {
throw new UnknownAnalysisProviderException(provider);
}
}
private void enrichWithRelationHypotheses(AnalyzeRequirementCommand command,
AnalysisResult result,
boolean persistHypotheses) {
if (result.getScores() == null) {
return;
}
result.setProvisionalRelations(analysisRelationGenerator.generate(result.getScores()));
if (persistHypotheses && !result.getProvisionalRelations().isEmpty()) {
hypothesisService.persistFromAnalysis(
result.getProvisionalRelations(),
null,
command.workspaceContext());
}
}
private void enrichWithArchitectureView(AnalyzeRequirementCommand command, AnalysisResult result) {
if (!command.includeArchitectureView() || result.getScores() == null) {
return;
}
RequirementArchitectureView archView = architectureViewService.build(
result.getScores(),
command.businessText(),
command.maxArchitectureNodes(),
result.getProvisionalRelations());
DiagramViewMetadata meta = ExportConfig.resolveViewMetadata(preferencesService);
archView.setViewTitle(meta.viewTitle());
archView.setViewDescription(meta.viewDescription());
archView.setContainmentEnabled(meta.containmentEnabled());
archView.setActiveRules(meta.activeRules());
result.setArchitectureView(archView);
}
private void populateViewContext(AnalyzeRequirementCommand command, AnalysisResult result) {
String effectiveUsername = command.workspaceContext().username();
String branch = repositoryStateService.resolveWorkspaceBranch(effectiveUsername);
result.setViewContext(repositoryStateService.getViewContext(
effectiveUsername,
branch,
command.workspaceContext()));
}
}