@sun-asterisk/impact-analyzer 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,484 @@
1
+ # Task 004: Fix Report Generator - Output Format Issues
2
+
3
+ **Status:** 📋 TODO
4
+ **Priority:** 🔴 HIGH
5
+ **Assignee:** AI Agent
6
+ **Created:** 2025-12-25
7
+
8
+ ---
9
+
10
+ ## 📝 Overview
11
+
12
+ Fix report generator to correctly display impact analysis data in both Markdown and JSON formats. Current issues:
13
+ 1. **Field name mismatches** - Using old field names (`table` instead of `tableName`)
14
+ 2. **Source code in reports** - Showing code snippets instead of just affected entities
15
+ 3. **JSON output broken** - Contains internal data structures not suitable for reports
16
+
17
+ ## 🎯 Goals
18
+
19
+ ### 1. Update Report Field Names
20
+ The database detector now returns spec-compliant output, but the report generator uses old field names.
21
+
22
+ **Current Issue:**
23
+ ```javascript
24
+ // Report uses:
25
+ db.table // ❌ Undefined
26
+ db.name // ❌ Undefined
27
+
28
+ // Should use:
29
+ db.tableName // ✅ Correct
30
+ db.modelName // ✅ Correct
31
+ db.modelPath // ✅ Correct
32
+ ```
33
+
34
+ ### 2. Remove Source Code from Reports
35
+ Reports should focus on **WHAT** changed, not HOW it changed.
36
+
37
+ **Show:**
38
+ - ✅ Endpoint paths: `GET /users/:id`
39
+ - ✅ Table names: `users`, `posts`
40
+ - ✅ Field names: `email`, `phone`
41
+ - ✅ Component names: `UserProfile.tsx`
42
+ - ✅ Impact severity: `critical`, `high`
43
+
44
+ **Do NOT Show:**
45
+ - ❌ Code snippets
46
+ - ❌ Diff output
47
+ - ❌ Method implementations
48
+ - ❌ File contents
49
+ - ❌ Git diff details
50
+
51
+ ### 3. Fix JSON Output
52
+ JSON output should be clean, structured data suitable for CI/CD integration.
53
+
54
+ **Requirements:**
55
+ - Remove internal data structures (AST, diff, oldContent)
56
+ - Remove file contents
57
+ - Focus on actionable insights
58
+ - Flatten nested structures where appropriate
59
+
60
+ ## 📋 Implementation Tasks
61
+
62
+ ### Phase 1: Audit Current Issues
63
+
64
+ - [ ] List all places using old field names (`table`, `name`)
65
+ - [ ] Identify where source code is being included
66
+ - [ ] Review JSON output structure
67
+ - [ ] Document expected vs actual output
68
+
69
+ **Audit Checklist:**
70
+ ```bash
71
+ # Find old field references
72
+ grep -n "\.table\b" core/report-generator.js
73
+ grep -n "\.name\b" core/report-generator.js
74
+
75
+ # Check what's in changes object
76
+ grep -n "changes\." core/report-generator.js
77
+
78
+ # Check JSON output
79
+ grep -n "JSON.stringify" index.js
80
+ ```
81
+
82
+ ### Phase 2: Fix Database Section
83
+
84
+ **File:** `core/report-generator.js`
85
+
86
+ #### Issue 1: Wrong Field Names
87
+
88
+ **Current Code:**
89
+ ```javascript
90
+ lines.push(`| \`${db.table}\` | ${db.operations.join(', ')} | ${fieldsDisplay} |`);
91
+ ```
92
+
93
+ **Fixed Code:**
94
+ ```javascript
95
+ lines.push(`| \`${db.tableName}\` | ${db.operations.join(', ')} | ${fieldsDisplay} |`);
96
+ ```
97
+
98
+ #### Issue 2: Show Model Information
99
+
100
+ **Add to report:**
101
+ ```javascript
102
+ // Database Impact Section
103
+ lines.push('| Table | Model | Impact Type | Severity | Operations |');
104
+ lines.push('|-------|-------|-------------|----------|-----------|');
105
+
106
+ dbImpacts.forEach(db => {
107
+ lines.push(`| \`${db.tableName}\` | ${db.modelName} | ${db.impactType} | ${db.severity} | ${db.operations.join(', ')} |`);
108
+ });
109
+ ```
110
+
111
+ **Detailed Section:**
112
+ ```javascript
113
+ dbImpacts.forEach(db => {
114
+ lines.push(`### \`${db.tableName}\` (${db.modelName})\n`);
115
+ lines.push(`- **Impact Type:** ${db.impactType}`);
116
+ lines.push(`- **Severity:** ${db.severity}`);
117
+ lines.push(`- **Operations:** ${db.operations.join(', ')}`);
118
+ lines.push(`- **Entity File:** ${db.modelPath}`);
119
+
120
+ if (db.fields && db.fields.length > 0) {
121
+ lines.push(`- **Affected Fields:** ${db.fields.map(f => `\`${f}\``).join(', ')}`);
122
+ }
123
+ lines.push('');
124
+ });
125
+ ```
126
+
127
+ ### Phase 3: Fix Console Report
128
+
129
+ **File:** `core/report-generator.js`
130
+
131
+ **Current Issue:**
132
+ ```javascript
133
+ console.log(` • ${d.table} (${d.operations.join(', ')})`); // ❌ undefined
134
+ ```
135
+
136
+ **Fix:**
137
+ ```javascript
138
+ console.log(` • ${d.tableName} (${d.impactType}, ${d.severity})`);
139
+ console.log(` Operations: ${d.operations.join(', ')}`);
140
+ if (d.fields && d.fields.length > 0) {
141
+ console.log(` Fields: ${d.fields.slice(0, 5).join(', ')}${d.fields.length > 5 ? '...' : ''}`);
142
+ }
143
+ ```
144
+
145
+ ### Phase 4: Clean JSON Output
146
+
147
+ **File:** `index.js`
148
+
149
+ **Current Issue:**
150
+ ```javascript
151
+ // This includes everything, including code and diffs
152
+ fs.writeFileSync(jsonOutput, JSON.stringify({ changes, impact }, null, 2));
153
+ ```
154
+
155
+ **Solution:** Create clean report structure
156
+
157
+ ```javascript
158
+ // Create clean JSON report
159
+ const jsonReport = reporter.generateJSONReport(changes, impact);
160
+ fs.writeFileSync(jsonOutput, JSON.stringify(jsonReport, null, 2));
161
+ ```
162
+
163
+ **Implementation in `report-generator.js`:**
164
+ ```javascript
165
+ /**
166
+ * Generate clean JSON report suitable for CI/CD
167
+ * Excludes source code, diffs, and internal data structures
168
+ */
169
+ generateJSONReport(changes, impact) {
170
+ return {
171
+ metadata: {
172
+ timestamp: new Date().toISOString(),
173
+ filesChanged: changes.changedFiles.length,
174
+ symbolsChanged: changes.changedSymbols?.length || 0,
175
+ },
176
+ summary: {
177
+ impactScore: impact.impactScore,
178
+ severity: impact.severity,
179
+ affectedEndpoints: impact.affectedEndpoints?.length || 0,
180
+ affectedTables: impact.databaseImpact?.length || 0,
181
+ affectedComponents: this.countComponents(changes.changedFiles),
182
+ },
183
+ endpoints: this.formatEndpointsForJSON(impact.affectedEndpoints),
184
+ database: this.formatDatabaseForJSON(impact.databaseImpact),
185
+ components: this.formatComponentsForJSON(changes.changedFiles),
186
+ logic: {
187
+ riskLevel: impact.logicImpact?.riskLevel || 'low',
188
+ directCallers: impact.logicImpact?.directCallers?.length || 0,
189
+ indirectCallers: impact.logicImpact?.indirectCallers?.length || 0,
190
+ }
191
+ };
192
+ }
193
+
194
+ formatEndpointsForJSON(endpoints) {
195
+ if (!endpoints || endpoints.length === 0) return [];
196
+
197
+ return endpoints.map(e => ({
198
+ method: e.method,
199
+ path: e.path,
200
+ controller: e.controller,
201
+ impactLevel: e.impactLevel,
202
+ // DO NOT include: affectedBy, callChain with code
203
+ }));
204
+ }
205
+
206
+ formatDatabaseForJSON(dbImpacts) {
207
+ if (!dbImpacts || dbImpacts.length === 0) return [];
208
+
209
+ return dbImpacts.map(db => ({
210
+ tableName: db.tableName,
211
+ modelName: db.modelName,
212
+ modelPath: db.modelPath,
213
+ impactType: db.impactType,
214
+ severity: db.severity,
215
+ operations: db.operations,
216
+ fields: db.fields || [],
217
+ // DO NOT include: changeSource with diff/content
218
+ }));
219
+ }
220
+
221
+ formatComponentsForJSON(changedFiles) {
222
+ const components = changedFiles.filter(f => this.isComponentFile(f));
223
+
224
+ return components.map(c => ({
225
+ path: c.path,
226
+ type: this.detectPageType(c.path),
227
+ status: c.status,
228
+ linesAdded: c.changes?.added || 0,
229
+ linesDeleted: c.changes?.deleted || 0,
230
+ // DO NOT include: content, oldContent, diff
231
+ }));
232
+ }
233
+
234
+ isComponentFile(file) {
235
+ const path = file.path.toLowerCase();
236
+ return (
237
+ path.includes('/page') || path.includes('/component') ||
238
+ path.includes('/view') || path.includes('/screen') ||
239
+ path.includes('.page.') || path.includes('.component.')
240
+ );
241
+ }
242
+
243
+ countComponents(changedFiles) {
244
+ return changedFiles.filter(f => this.isComponentFile(f)).length;
245
+ }
246
+ ```
247
+
248
+ ### Phase 5: Remove Code from Markdown Report
249
+
250
+ **File:** `core/report-generator.js`
251
+
252
+ **Current Issues to Fix:**
253
+
254
+ 1. **Changed Files Section** - Showing diff snippets
255
+ ```javascript
256
+ // REMOVE OR SIMPLIFY
257
+ generateChangedFilesSection(changedFiles) {
258
+ // Don't show: oldContent, content, diff
259
+ // Only show: path, status, lines changed
260
+ }
261
+ ```
262
+
263
+ 2. **Logic Impact Section** - Showing method details
264
+ ```javascript
265
+ // Keep simple
266
+ lines.push(`**Direct Callers:** ${logicImpact.directCallers.length}`);
267
+ lines.push(`**Indirect Callers:** ${logicImpact.indirectCallers.length}`);
268
+ // Don't list all method names with signatures
269
+ ```
270
+
271
+ **Clean Changed Files Section:**
272
+ ```javascript
273
+ generateChangedFilesSection(changedFiles) {
274
+ const lines = ['## 📝 Changed Files\n'];
275
+
276
+ lines.push(`**Total Files Changed:** ${changedFiles.length}\n`);
277
+
278
+ lines.push('| File | Type | Status | Changes |');
279
+ lines.push('|------|------|--------|---------|');
280
+
281
+ changedFiles.forEach(f => {
282
+ const type = f.type || 'source';
283
+ const changes = `+${f.changes?.added || 0} -${f.changes?.deleted || 0}`;
284
+ const statusEmoji = this.getStatusEmoji(f.status);
285
+ lines.push(`| ${statusEmoji} ${f.path} | ${type} | ${f.status} | ${changes} |`);
286
+ });
287
+
288
+ return lines.join('\n');
289
+ }
290
+ ```
291
+
292
+ ## ✅ Acceptance Criteria
293
+
294
+ ### Markdown Report
295
+ - [ ] Database section uses `tableName`, `modelName`, `modelPath`
296
+ - [ ] Database section shows `impactType` and `severity`
297
+ - [ ] No source code snippets
298
+ - [ ] No diff output
299
+ - [ ] Only shows entity names and affected fields
300
+
301
+ ### Console Report
302
+ - [ ] Database section uses correct field names
303
+ - [ ] Shows severity for each table
304
+ - [ ] Compact, readable format
305
+ - [ ] No code output
306
+
307
+ ### JSON Report
308
+ - [ ] Clean structure suitable for CI/CD
309
+ - [ ] No `content`, `oldContent`, `diff` fields
310
+ - [ ] Uses correct field names (`tableName` not `table`)
311
+ - [ ] Flat structure where possible
312
+ - [ ] Includes metadata (timestamp, counts)
313
+ - [ ] Valid JSON format
314
+
315
+ ## 🧪 Testing
316
+
317
+ ### Manual Tests
318
+
319
+ **Test 1: Markdown Report Format**
320
+ ```bash
321
+ node index.js --input=src --base=origin/main --output=test-report.md
322
+
323
+ # Check report:
324
+ cat test-report.md
325
+
326
+ # Expected:
327
+ # - Database section has tableName, modelName
328
+ # - No code snippets
329
+ # - Clean table format
330
+ ```
331
+
332
+ **Test 2: JSON Report Format**
333
+ ```bash
334
+ node index.js --input=src --base=origin/main --json=test-report.json
335
+
336
+ # Check JSON:
337
+ cat test-report.json | jq .
338
+
339
+ # Expected:
340
+ # - Valid JSON
341
+ # - No content/diff fields
342
+ # - Clean database section with tableName
343
+ ```
344
+
345
+ **Test 3: Console Output**
346
+ ```bash
347
+ node index.js --input=src --base=origin/main
348
+
349
+ # Expected:
350
+ # - Database impact shows tableName
351
+ # - No undefined values
352
+ # - Clean, readable output
353
+ ```
354
+
355
+ ## 📊 Expected Output Examples
356
+
357
+ ### Markdown Report
358
+
359
+ #### Database Section
360
+ ```markdown
361
+ ## 💾 Database Impact
362
+
363
+ **Total Tables Affected:** 2
364
+
365
+ | Table | Model | Impact Type | Severity | Operations |
366
+ |-------|-------|-------------|----------|-----------|
367
+ | `users` | UserEntity | schema | critical | SELECT, INSERT, UPDATE |
368
+ | `posts` | PostEntity | query | medium | INSERT |
369
+
370
+ ### Details
371
+
372
+ #### `users` (UserEntity)
373
+ - **Impact Type:** schema
374
+ - **Severity:** critical
375
+ - **Operations:** SELECT, INSERT, UPDATE
376
+ - **Entity File:** src/entities/user.entity.ts
377
+ - **Affected Fields:** `email`, `phone`, `updatedAt`
378
+
379
+ #### `posts` (PostEntity)
380
+ - **Impact Type:** query
381
+ - **Severity:** medium
382
+ - **Operations:** INSERT
383
+ - **Entity File:** src/entities/post.entity.ts
384
+ ```
385
+
386
+ ### JSON Report
387
+ ```json
388
+ {
389
+ "metadata": {
390
+ "timestamp": "2025-12-25T03:00:00.000Z",
391
+ "filesChanged": 5,
392
+ "symbolsChanged": 8
393
+ },
394
+ "summary": {
395
+ "impactScore": 75,
396
+ "severity": "high",
397
+ "affectedEndpoints": 3,
398
+ "affectedTables": 2,
399
+ "affectedComponents": 1
400
+ },
401
+ "endpoints": [
402
+ {
403
+ "method": "GET",
404
+ "path": "/users/:id",
405
+ "controller": "UserController.getUser",
406
+ "impactLevel": "high"
407
+ }
408
+ ],
409
+ "database": [
410
+ {
411
+ "tableName": "users",
412
+ "modelName": "UserEntity",
413
+ "modelPath": "src/entities/user.entity.ts",
414
+ "impactType": "schema",
415
+ "severity": "critical",
416
+ "operations": ["SELECT", "INSERT", "UPDATE"],
417
+ "fields": ["email", "phone", "updatedAt"]
418
+ }
419
+ ],
420
+ "components": [
421
+ {
422
+ "path": "src/pages/UserProfile.tsx",
423
+ "type": "page",
424
+ "status": "modified",
425
+ "linesAdded": 15,
426
+ "linesDeleted": 3
427
+ }
428
+ ],
429
+ "logic": {
430
+ "riskLevel": "medium",
431
+ "directCallers": 5,
432
+ "indirectCallers": 12
433
+ }
434
+ }
435
+ ```
436
+
437
+ ### Console Output
438
+ ```
439
+ 💾 DATABASE IMPACT:
440
+ • users (schema, critical)
441
+ Operations: SELECT, INSERT, UPDATE
442
+ Fields: email, phone, updatedAt
443
+ • posts (query, medium)
444
+ Operations: INSERT
445
+ ```
446
+
447
+ ## 🎯 Definition of Done
448
+
449
+ - [ ] All field name mismatches fixed
450
+ - [ ] No source code in reports
451
+ - [ ] JSON output uses clean structure
452
+ - [ ] Markdown report shows proper database info
453
+ - [ ] Console report uses correct fields
454
+ - [ ] All tests pass
455
+ - [ ] Reports are readable and actionable
456
+ - [ ] JSON is valid and CI/CD friendly
457
+
458
+ ## 🔗 References
459
+
460
+ - **Current Code:** `core/report-generator.js`, `index.js`
461
+ - **Spec:** `.specify/specs/features/database-impact-detection.md` (Section 5 - Output Schema)
462
+ - **Task 002:** `.specify/tasks/task-002-database-detector.md` (Database output format)
463
+
464
+ ## 📝 Notes
465
+
466
+ ### Report Best Practices
467
+
468
+ 1. **Focus on "What" not "How"**
469
+ - ✅ "Table `users` changed"
470
+ - ❌ "Line 45: `email: string;` added"
471
+
472
+ 2. **Keep JSON Clean**
473
+ - ✅ Include: tableName, operations, severity
474
+ - ❌ Exclude: diff, content, oldContent, AST
475
+
476
+ 3. **Make Reports Actionable**
477
+ - Show severity so developers know priority
478
+ - Show affected entities so QA knows what to test
479
+ - Show file paths for quick navigation
480
+
481
+ ---
482
+
483
+ **Last Updated:** 2025-12-25
484
+ **Implementation Status:** TODO
package/README.md CHANGED
@@ -151,7 +151,7 @@ npx @sun-asterisk/impact-analyzer --input=src --base=abc123 --head=def456
151
151
 
152
152
  ## CI/CD Integration
153
153
 
154
- ### GitHub Actions
154
+ ### GitHub Actions (Recommended - Simple)
155
155
 
156
156
  ```yaml
157
157
  name: Impact Analysis
@@ -165,7 +165,7 @@ jobs:
165
165
  steps:
166
166
  - uses: actions/checkout@v4
167
167
  with:
168
- fetch-depth: 0 # Fetch full history
168
+ fetch-depth: 2 # Fetch current commit + parent
169
169
 
170
170
  - uses: actions/setup-node@v3
171
171
  with:
@@ -175,22 +175,16 @@ jobs:
175
175
  run: |
176
176
  npx @sun-asterisk/impact-analyzer \
177
177
  --input=src \
178
- --base=origin/${{ github.base_ref }} \
179
- --output=impact-report.md \
180
- --json=impact-report.json
178
+ --base=origin/${{ github.event.pull_request.base.ref }} \
179
+ --head=HEAD \
180
+ --output=impact-report.md
181
181
 
182
- - name: Comment PR
183
- uses: actions/github-script@v6
182
+ - name: Upload impact reports
183
+ uses: actions/upload-artifact@v4
184
184
  with:
185
- script: |
186
- const fs = require('fs');
187
- const report = fs.readFileSync('impact-report.md', 'utf8');
188
- github.rest.issues.createComment({
189
- issue_number: context.issue.number,
190
- owner: context.repo.owner,
191
- repo: context.repo.repo,
192
- body: report
193
- });
185
+ name: impact-reports-${{ github.sha }}
186
+ path: impact-report.md
187
+ retention-days: 30
194
188
  ```
195
189
 
196
190
  ### GitLab CI
@@ -200,11 +194,12 @@ impact-analysis:
200
194
  stage: test
201
195
  image: node:18
202
196
  variables:
203
- GIT_DEPTH: 0 # Fetch full history
197
+ GIT_DEPTH: 2 # Fetch current + parent commit
204
198
  script:
205
199
  - npx @sun-asterisk/impact-analyzer
206
200
  --input=src
207
201
  --base=origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME
202
+ --head=HEAD
208
203
  --output=impact-report.md
209
204
  --json=impact-report.json
210
205
  artifacts:
@@ -227,6 +222,7 @@ pipeline {
227
222
  npx @sun-asterisk/impact-analyzer \
228
223
  --input=src \
229
224
  --base=origin/main \
225
+ --head=HEAD \
230
226
  --output=impact-report.md \
231
227
  --json=impact-report.json
232
228
  '''
@@ -236,8 +232,6 @@ pipeline {
236
232
  }
237
233
  ```
238
234
 
239
- ## Report Output
240
-
241
235
  ### Severity Levels
242
236
 
243
237
  - 🟢 **LOW** (0-20) - Minor changes