Skip to content

Commit e4ad303

Browse files
alpslaclaude
andcommitted
SESSION 112: Integrate V9GroupedReportFormatter, deprecate V9ReportFormatterFinal
Key changes: - V9AnalysisService now uses V9GroupedReportFormatter exclusively - V9ReportFormatterFinal moved to analyzers/deprecated/ folder - Updated v9-base-analyzer, v9-integrated-analyzer, v9-report-compiler - Removed useGroupedReport option (always uses grouped formatter) - Session 112 enhancements now active: progressHistory, tier support, IDE fix files The V9GroupedReportFormatter provides: - Progress history tracking for score trends - User tier support (basic/pro/enterprise) - Better issue grouping - IDE integration files (LSP, SARIF) - Community impact tracking - XP/achievements system Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 7a44f8f commit e4ad303

8 files changed

Lines changed: 7594 additions & 68 deletions

File tree

docs/sample-reports/v9-session112-basic-report.md

Lines changed: 7450 additions & 0 deletions
Large diffs are not rendered by default.

packages/agents/src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,10 @@ export { V9KotlinAnalyzer } from './two-branch/analyzers/v9-kotlin-analyzer';
7575
export * from './two-branch/analyzers/v9-types';
7676

7777
// Export report formatters
78-
export { V9ReportFormatterFinal } from './two-branch/analyzers/v9-report-formatter';
78+
// SESSION 112: V9GroupedReportFormatter is the primary formatter
7979
export { V9GroupedReportFormatter } from './two-branch/analyzers/v9-grouped-report-formatter';
80+
// NOTE: V9ReportFormatterFinal has been deprecated and moved to analyzers/deprecated/
81+
// If you need it for backward compatibility, import directly from that path
8082

8183
// Export other working modules
8284
export * from './standard/utils';

packages/agents/src/two-branch/analyzers/v9-report-formatter.ts renamed to packages/agents/src/two-branch/analyzers/deprecated/v9-report-formatter.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
/**
2-
* V9 Report Formatter - Final Production Version
3-
*
2+
* @deprecated SESSION 112 - This formatter has been replaced by V9GroupedReportFormatter
3+
*
4+
* ARCHIVED: 2026-01-19
5+
* REASON: V9GroupedReportFormatter provides:
6+
* - Progress history tracking
7+
* - User tier support (basic/pro/enterprise)
8+
* - Better issue grouping
9+
* - IDE integration files
10+
* - Community impact tracking
11+
* - XP/achievements system
12+
*
13+
* DO NOT USE FOR NEW CODE - Use V9GroupedReportFormatter instead
14+
* Location: ../v9-grouped-report-formatter.ts
15+
*
16+
* ---
17+
* V9 Report Formatter - Final Production Version (DEPRECATED)
18+
*
419
* This formatter generates the complete V9 report with all improvements:
520
* - Summary statistics
621
* - Proper category breakdown

packages/agents/src/two-branch/analyzers/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
// Factory - ALWAYS use this to create analyzers
2323
export { V9AnalyzerFactory, type SupportedLanguage } from './v9-analyzer-factory';
2424

25-
// Report Generation - Use the MAIN formatter (formerly v9-report-formatter-final)
26-
export { V9ReportFormatterFinal as V9ReportFormatter } from './v9-report-formatter';
25+
// Report Generation - SESSION 112: V9GroupedReportFormatter is now the primary formatter
26+
export { V9GroupedReportFormatter as V9ReportFormatter } from './v9-grouped-report-formatter';
27+
export { V9GroupedReportFormatter } from './v9-grouped-report-formatter';
2728
export { V9PRCommentGenerator } from './v9-pr-comment-generator';
29+
// NOTE: V9ReportFormatterFinal has been deprecated and moved to deprecated/v9-report-formatter.ts
2830

2931
// Core Types
3032
export * from './v9-types';

packages/agents/src/two-branch/analyzers/v9-base-analyzer.ts

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ import { V9ScoringCalculator } from './v9-scoring-calculator';
3232
import { V9IssueComparator } from './v9-issue-comparator';
3333
import { V9EducationalResources } from './v9-educational-resources';
3434
import { V9BusinessImpact } from './v9-business-impact';
35-
import { V9ReportFormatterFinal as V9ReportFormatter } from './v9-report-formatter';
35+
// SESSION 112: Use V9GroupedReportFormatter as the primary formatter
36+
import { V9GroupedReportFormatter as V9ReportFormatter } from './v9-grouped-report-formatter';
3637

3738
// Import utilities
3839
import { getRepoManager, getFileSelector } from '../utils/repository-utils-factory';
@@ -261,8 +262,42 @@ export abstract class V9BaseAnalyzer {
261262
analyzedAt: timestamp
262263
};
263264

264-
const report = await this.reportFormatter.generateCompleteReport(result, completeMetadata, config.name);
265-
await this.saveReport(report, prNumber);
265+
// SESSION 112: Use V9GroupedReportFormatter.generateGroupedReport
266+
// Convert AnalysisResult issues to EnrichedIssue format for the grouped formatter
267+
const convertToEnrichedIssue = (i: Issue, cat: string) => ({
268+
file: i.file,
269+
line: i.line,
270+
column: undefined,
271+
rule: i.rule || i.title,
272+
tool: i.tool,
273+
severity: i.severity as 'critical' | 'high' | 'medium' | 'low',
274+
message: i.description || i.title,
275+
category: cat,
276+
detectedCategory: i.category as string,
277+
snippet: i.codeSnippet
278+
});
279+
280+
const allIssues = [
281+
...newIssues.map(i => convertToEnrichedIssue(i, 'NEW')),
282+
...existingIssues.map(i => convertToEnrichedIssue(i, 'EXISTING_REST')),
283+
...resolvedIssues.map(i => convertToEnrichedIssue(i, 'RESOLVED'))
284+
];
285+
286+
// Import groupIssues to create groups
287+
const { groupIssues } = await import('../utils/issue-grouping');
288+
const groupingResult = groupIssues(allIssues);
289+
290+
// Generate grouped report
291+
const reportOutput = await this.reportFormatter.generateGroupedReport(
292+
allIssues,
293+
groupingResult.groups,
294+
{
295+
...completeMetadata,
296+
decision: result.decision,
297+
blockingCount: blockingIssues.length
298+
}
299+
);
300+
await this.saveReport(reportOutput.markdown, prNumber);
266301

267302
this.logger.log('✅ Analysis complete!');
268303

packages/agents/src/two-branch/analyzers/v9-integrated-analyzer.ts

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
import { RedisToolOutputManager, ToolOutput } from '../utils/redis-tool-output-manager';
77
import { KubernetesRepositoryManager } from '../utils/kubernetes-repository-manager';
8-
import { V9ReportFormatterFinal } from './v9-report-formatter';
9-
import { V9GroupedReportFormatter } from './v9-grouped-report-formatter'; // Phase B+C: Cost-optimized reports
8+
// SESSION 112: V9ReportFormatterFinal deprecated, use V9GroupedReportFormatter only
9+
import { V9GroupedReportFormatter } from './v9-grouped-report-formatter';
1010
import { DynamicModelSelector } from '../services/dynamic-model-selector';
1111
import { SkillScoreManager } from './v9-skill-score-manager'; // Moved to V9 core
1212
import { V9CleanupService } from '../services/v9-cleanup-service'; // Automatic cleanup after analysis
@@ -42,8 +42,8 @@ interface AIInsight {
4242
export class V9IntegratedAnalyzer {
4343
private redisManager: RedisToolOutputManager;
4444
private repoManager: KubernetesRepositoryManager;
45-
private reportFormatter: V9ReportFormatterFinal;
46-
private groupedFormatter: V9GroupedReportFormatter; // Phase B+C: Cost-optimized formatter
45+
// SESSION 112: Unified to single formatter
46+
private reportFormatter: V9GroupedReportFormatter;
4747
private modelSelector: DynamicModelSelector;
4848
private cleanupService: V9CleanupService; // Automatic cleanup service
4949
private aiClient = getResilientAIClient();
@@ -53,21 +53,13 @@ export class V9IntegratedAnalyzer {
5353
private detectedLanguage = 'unknown';
5454
private detectedRepoSize: 'small' | 'medium' | 'large' | 'enterprise' = 'medium';
5555

56-
// Phase B+C: Report format configuration
57-
private useGroupedReport = true; // Default to grouped (99.8% cost savings)
56+
// SESSION 112: Unified formatter (V9GroupedReportFormatter replaces V9ReportFormatterFinal)
5857

59-
constructor(options?: { useGroupedReport?: boolean }) {
58+
constructor() {
6059
this.redisManager = new RedisToolOutputManager();
6160
this.repoManager = new KubernetesRepositoryManager();
62-
this.reportFormatter = new V9ReportFormatterFinal();
63-
this.groupedFormatter = new V9GroupedReportFormatter(); // Phase B+C: Initialize grouped formatter
64-
65-
// Allow override via options or environment variable
66-
if (options?.useGroupedReport !== undefined) {
67-
this.useGroupedReport = options.useGroupedReport;
68-
} else if (process.env.V9_USE_FULL_REPORT === 'true') {
69-
this.useGroupedReport = false;
70-
}
61+
// SESSION 112: Use only V9GroupedReportFormatter
62+
this.reportFormatter = new V9GroupedReportFormatter();
7163

7264
// Use the existing DynamicModelSelector that fetches from Supabase
7365
this.modelSelector = new DynamicModelSelector(process.env.OPENROUTER_API_KEY);
@@ -468,7 +460,7 @@ and actionable recommendations. Focus on business value and team productivity.`;
468460
aiInsights: data.aiInsights
469461
},
470462
{
471-
useGroupedReport: this.useGroupedReport,
463+
// SESSION 112: useGroupedReport is deprecated (always true now)
472464
modelConfigResolver: this.modelConfigResolver,
473465
detectedLanguage: this.detectedLanguage,
474466
detectedRepoSize: this.detectedRepoSize,
@@ -529,7 +521,7 @@ and actionable recommendations. Focus on business value and team productivity.`;
529521
parallelExecution: true,
530522
parallelFixGeneration: true,
531523
fixGenerationTime: `${(result.completeMetadata.fixGenerationTime / 1000).toFixed(2)}s`,
532-
reportType: this.useGroupedReport ? 'grouped' : 'full',
524+
reportType: 'grouped', // SESSION 112: Always grouped
533525
agentMetrics: (result.completeMetadata.agentsUsed || []).map((a: any) => ({
534526
agent: a.agentName,
535527
issues: a.issuesFound,
@@ -543,7 +535,8 @@ and actionable recommendations. Focus on business value and team productivity.`;
543535
}))
544536
},
545537

546-
...(this.useGroupedReport && result.attachments ? {
538+
// SESSION 112: Always include attachments (grouped report is always used)
539+
...(result.attachments ? {
547540
attachments: result.attachments.locationAttachments,
548541
ideFixFiles: result.attachments.ideFixFiles,
549542
issueGroupMapping: result.attachments.mapping

packages/agents/src/two-branch/api/v9-analysis-service.ts

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import {
3737
} from '../utils/security-utils';
3838
import { SpecializedAgentFactory } from '../agents/specialized-agents';
3939
import { V9EducationalResources } from '../analyzers/v9-educational-resources';
40-
import { V9ReportFormatterFinal } from '../analyzers/v9-report-formatter';
40+
import { V9GroupedReportFormatter } from '../analyzers/v9-grouped-report-formatter';
4141
import { ModelConfigResolver } from '../../standard/orchestrator/model-config-resolver';
4242
import { CodeSnippetExtractor } from '../utils/code-snippet-extractor';
4343
import { groupIssues, prioritizeGroups, generateGroupingSummary } from '../utils/issue-grouping';
@@ -879,51 +879,78 @@ export class V9AnalysisService {
879879
console.log(`[Report] Scanner guidance saved`);
880880
}
881881

882-
// Generate main markdown report using existing formatter
882+
// SESSION 112: Use V9GroupedReportFormatter (with progressHistory, tier support)
883+
// Replaces V9ReportFormatterFinal for all new reports
883884
try {
884-
const formatter = new V9ReportFormatterFinal();
885-
886-
// SESSION 92: Split issues by category for formatter
887-
// V9ReportFormatterFinal expects newIssues, existingIssues, resolvedIssues arrays
888-
const newIssues = issues.filter(i => i.category === 'NEW');
889-
const existingModifiedIssues = issues.filter(i => i.category === 'EXISTING_MODIFIED');
890-
const existingRestIssues = issues.filter(i => i.category === 'EXISTING_REST');
891-
const resolvedIssues = issues.filter(i => i.category === 'RESOLVED');
892-
893-
// Build result object for formatter with proper structure
894-
const analysisResult: any = {
895-
issues,
896-
newIssues,
897-
existingIssues: [...existingModifiedIssues, ...existingRestIssues],
898-
resolvedIssues,
885+
const formatter = new V9GroupedReportFormatter();
886+
887+
// Generate issue groups for the formatter
888+
const groupingResult = groupIssues(issues);
889+
890+
// Build metadata object for grouped formatter
891+
const reportMetadata = {
892+
repository: metadata.repository,
893+
repoUrl: metadata.repoUrl,
894+
repoPath: metadata.repoPath,
895+
prNumber: metadata.prNumber,
896+
prTitle: metadata.prTitle,
897+
branch: metadata.branch || metadata.prBranch,
898+
baseBranch: metadata.baseBranch,
899+
prAuthor: metadata.prAuthor,
900+
prAuthorEmail: metadata.prAuthorEmail,
901+
organizationName: metadata.organizationName,
902+
totalFiles: metadata.totalFiles || 0,
903+
totalLinesOfCode: metadata.totalLinesOfCode,
904+
filesModified: metadata.filesModified,
905+
linesAdded: metadata.linesAdded,
906+
linesDeleted: metadata.linesDeleted,
907+
languageBreakdown: metadata.languageBreakdown,
899908
decision,
900-
score: Math.max(0, 100 - (blockingIssues.length * 10) - (newIssues.length * 0.5)),
901-
categoryScores: {},
902-
duration: 0,
903-
cost: 0
909+
blockingCount: blockingIssues.length,
910+
totalDuration: metadata.totalDuration || 0,
911+
cloneTime: metadata.cloneTime,
912+
analysisTime: metadata.analysisTime,
913+
reportGenerationTime: metadata.reportGenerationTime,
914+
analyzedAt: new Date().toISOString(),
915+
analyzerVersion: metadata.analyzerVersion || '9.0.0',
916+
toolPerformance: metadata.toolPerformance || [],
917+
agentPerformance: metadata.agentPerformance,
918+
modelsUsed: metadata.modelsUsed,
919+
userTier: metadata.userTier || 'basic'
904920
};
905921

906-
// Build metadata object for formatter
907-
const reportMetadata: any = {
908-
...metadata,
909-
analysisTimestamp: new Date().toISOString(),
910-
totalDuration: 0
911-
};
912-
913-
const report = await formatter.generateCompleteReport(
914-
analysisResult,
915-
reportMetadata,
916-
metadata.language
922+
// Generate grouped report with all Session 112 enhancements
923+
const reportOutput = await formatter.generateGroupedReport(
924+
issues,
925+
groupingResult.groups,
926+
reportMetadata
917927
);
918928

919929
// lgtm[js/path-injection] - outputDir is internally computed, 'report.md' is hardcoded
920930
const markdownPath = path.join(outputDir, 'report.md');
921-
fs.writeFileSync(markdownPath, report); // lgtm[js/path-injection]
931+
fs.writeFileSync(markdownPath, reportOutput.markdown); // lgtm[js/path-injection]
922932
console.log(`[Report] Markdown saved`);
923933

934+
// Save IDE fix files if available
935+
if (reportOutput.ideFixFiles && reportOutput.ideFixFiles.length > 0) {
936+
for (const fixFile of reportOutput.ideFixFiles) {
937+
const fixPath = path.join(outputDir, fixFile.filename);
938+
fs.writeFileSync(fixPath, JSON.stringify(fixFile.content, null, 2));
939+
}
940+
console.log(`[Report] ${reportOutput.ideFixFiles.length} IDE fix files saved`);
941+
}
942+
943+
// Save group mapping for API consumers
944+
if (reportOutput.mapping) {
945+
const mappingPath = path.join(outputDir, 'issue-groups.json');
946+
fs.writeFileSync(mappingPath, JSON.stringify(reportOutput.mapping, null, 2));
947+
console.log(`[Report] Issue group mapping saved`);
948+
}
949+
924950
return { markdown: markdownPath };
925951
} catch (error: any) {
926952
console.log(` ⚠️ Report generation error: ${error.message}`);
953+
console.error(error);
927954
return {};
928955
}
929956
}

packages/agents/src/two-branch/services/v9-report-compiler.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
import { groupIssues } from '../utils/issue-grouping';
1818
import { SkillScoreManager } from '../analyzers/v9-skill-score-manager';
19+
// SESSION 112: V9GroupedReportFormatter is now the only formatter
1920
import { V9GroupedReportFormatter } from '../analyzers/v9-grouped-report-formatter';
20-
import { V9ReportFormatterFinal } from '../analyzers/v9-report-formatter';
2121
import { ModelConfigResolver } from '../../standard/orchestrator/model-config-resolver';
2222
import { enrichIssuesWithAI } from '../report/ai-enrichment';
2323

@@ -42,6 +42,7 @@ export interface CompileReportInput {
4242
}
4343

4444
export interface CompileReportOptions {
45+
/** @deprecated SESSION 112: Always uses grouped report now */
4546
useGroupedReport?: boolean;
4647
modelConfigResolver?: ModelConfigResolver;
4748
detectedLanguage?: string;
@@ -93,7 +94,8 @@ export async function compileV9Report(
9394
console.log(`[DEBUG-PR#] ======================================\n`);
9495

9596
const {
96-
useGroupedReport = true,
97+
// SESSION 112: useGroupedReport is deprecated, always true
98+
useGroupedReport: _useGroupedReportDeprecated = true,
9799
modelConfigResolver,
98100
detectedLanguage = 'unknown',
99101
detectedRepoSize = 'medium',
@@ -503,11 +505,12 @@ export async function compileV9Report(
503505
// Add team members (placeholder - requires Supabase)
504506
completeMetadata.teamMembers = discoverTeamFromGit(['/tmp/kafka-repo']);
505507

506-
// Generate report
508+
// Generate report - SESSION 112: Always use V9GroupedReportFormatter
507509
let markdown: string;
508510
let reportAttachments: any = {};
509511

510-
if (useGroupedReport) {
512+
// Always use grouped report (V9ReportFormatterFinal is deprecated)
513+
{
511514
const allProcessedIssues = [...formattedNewIssues, ...formattedExistingIssues, ...formattedResolvedIssues];
512515

513516
// BUG #89 DEBUG: Check categories in allProcessedIssues
@@ -581,16 +584,15 @@ export async function compileV9Report(
581584
ideFixFiles: result.ideFixFiles,
582585
mapping: result.mapping
583586
};
584-
} else {
585-
const fullFormatter = new V9ReportFormatterFinal();
586-
markdown = await fullFormatter.generateCompleteReport(analysisResult, completeMetadata, detectedLanguage);
587587
}
588+
// SESSION 112: Removed else branch - V9ReportFormatterFinal is deprecated
588589

589590
return {
590591
analysisResult,
591592
completeMetadata: {
592593
...completeMetadata,
593-
...(useGroupedReport && reportAttachments ? {
594+
// SESSION 112: Always include attachments (grouped report is always used)
595+
...(reportAttachments ? {
594596
attachments: reportAttachments.locationAttachments,
595597
ideFixFiles: reportAttachments.ideFixFiles,
596598
issueGroupMapping: reportAttachments.mapping

0 commit comments

Comments
 (0)