문서 품질 critic와 golden 회귀를 고도화해 PPTX·HTML·DOCX·XLSX 마감 품질을 강화한다
- ArtifactQualityReviewService를 확장해 HTML의 board/strategy decision gap, DOCX evidence table·callout 부족, XLSX dashboard trend·variance·sheet summary·headline tile 부족을 개별 이슈로 판정하도록 보강 - ArtifactRepairGuideService와 DeckRepairGuideService를 보강해 decision summary, next steps, evidence table, trend/variance, dashboard tile 등 실제 보강 행동을 바로 제안하는 repair guide를 반환하도록 정리 - ExcelSkill review 입력을 세분화하고 Html/PPT golden 테스트를 strategy brief, PMO steering 시나리오까지 확대해 문서군 golden 회귀 범위를 넓힘 - 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_finish_batch\\ -p:IntermediateOutputPath=obj\\verify_doc_finish_batch\\ / dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal (ArtifactQualityReviewServiceTests, ArtifactRepairGuideServiceTests, DeckQualityReviewServiceTests, DeckRepairGuideServiceTests, HtmlSkillGoldenReportTests, PptxSkillGoldenDeckTests, DocxSkillGoldenDocumentTests, ExcelSkillGoldenWorkbookTests) -p:OutputPath=bin\\verify_doc_finish_batch_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_finish_batch_tests\
This commit is contained in:
@@ -1962,3 +1962,10 @@ MIT License
|
||||
- 남은 고도화를 한 번에 끝내기 위한 통합 마감 계획을 확정했습니다. 다음 배치는 `문서 포맷 최종 마감 -> 에이전틱 루프 iteration pipeline 분리 -> 개발언어 no-LSP fallback 심화 -> 명령/스킬 합성 및 릴리즈 게이트` 순서로 진행합니다.
|
||||
- 기준 레퍼런스는 `claude-code`의 [query.ts](/E:/AX%20Copilot%20-%20Codex/claw-code/claw-code-f5a40b86dede580f6543bf8926c9af017eea9409/src/query.ts), [QueryEngine.ts](/E:/AX%20Copilot%20-%20Codex/claw-code/claw-code-f5a40b86dede580f6543bf8926c9af017eea9409/src/QueryEngine.ts), [toolResultStorage.ts](/E:/AX%20Copilot%20-%20Codex/claw-code/claw-code-f5a40b86dede580f6543bf8926c9af017eea9409/src/utils/toolResultStorage.ts), [messageQueueManager.ts](/E:/AX%20Copilot%20-%20Codex/claw-code/claw-code-f5a40b86dede580f6543bf8926c9af017eea9409/src/utils/messageQueueManager.ts), [commands.ts](/E:/AX%20Copilot%20-%20Codex/claw-code/claw-code-f5a40b86dede580f6543bf8926c9af017eea9409/src/commands.ts)이며, AX 쪽에서는 `AgentLoopService`, `AgentCommandQueue`, `AgentQueryContextBuilder`, `ContextCondenser`, `CodeLanguageCatalog`, `SlashCommandCatalog`, `SkillService`, 각 문서 생성 스킬을 마감 대상으로 잡았습니다.
|
||||
- 완료 기준은 `dotnet build` 경고 0 / 오류 0, `PPTX/XLSX/DOCX/HTML golden`, `중단/재개/권한/branch/replay`, `언어 fallback` 회귀까지 모두 통과하는 상태입니다.
|
||||
|
||||
업데이트: 2026-04-15 10:24 (KST)
|
||||
- 문서 품질 critic를 한 단계 더 구체화했습니다. [ArtifactQualityReviewService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/ArtifactQualityReviewService.cs)는 이제 HTML의 `board_report`/`strategy_brief` 결정 블록 누락, DOCX 장문 문서의 evidence table·callout 부족, XLSX dashboard workbook의 trend/variance framing·sheet summary·headline tile 부족을 각각 별도 이슈로 판정합니다.
|
||||
- 보정 가이드도 포맷별로 더 실행 가능하게 정리했습니다. [ArtifactRepairGuideService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/ArtifactRepairGuideService.cs)와 [DeckRepairGuideService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/DeckRepairGuideService.cs)는 decision summary, trend/variance block, evidence table, next steps 같은 실제 보강 항목을 바로 제안하도록 보강했습니다.
|
||||
- golden 회귀를 확대했습니다. [HtmlSkillGoldenReportTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/HtmlSkillGoldenReportTests.cs)에 strategy brief 시나리오를 추가했고, [PptxSkillGoldenDeckTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/PptxSkillGoldenDeckTests.cs)는 PMO steering deck까지 고정했습니다. [ArtifactQualityReviewServiceTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/ArtifactQualityReviewServiceTests.cs), [ArtifactRepairGuideServiceTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/ArtifactRepairGuideServiceTests.cs), [DeckQualityReviewServiceTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/DeckQualityReviewServiceTests.cs), [DeckRepairGuideServiceTests.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot.Tests/Services/DeckRepairGuideServiceTests.cs)도 함께 확장했습니다.
|
||||
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_finish_batch\\ -p:IntermediateOutputPath=obj\\verify_doc_finish_batch\\` 경고 0 / 오류 0
|
||||
- 검증: `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ArtifactQualityReviewServiceTests|ArtifactRepairGuideServiceTests|DeckQualityReviewServiceTests|DeckRepairGuideServiceTests|HtmlSkillGoldenReportTests|PptxSkillGoldenDeckTests|DocxSkillGoldenDocumentTests|ExcelSkillGoldenWorkbookTests" -p:OutputPath=bin\\verify_doc_finish_batch_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_finish_batch_tests\\` 통과 26
|
||||
|
||||
@@ -1078,3 +1078,33 @@ UI ?붿옄???洹쒕え 由ы뙥?좊쭅 ???꾪뿕 ?묒뾽 ??湲곕줉???덉쟾
|
||||
- 문서 golden: `PPTX/XLSX/DOCX/HTML`
|
||||
- 루프/큐/컨텍스트: `중단/재개/권한/branch/replay`
|
||||
- 언어 fallback: `CodeLanguageCatalogTests`, `WorkspaceContextGeneratorTests`, 관련 fallback 회귀
|
||||
|
||||
업데이트: 2026-04-15 10:24 (KST)
|
||||
- 문서 critic 세부화:
|
||||
- `ArtifactQualityReviewService.cs`
|
||||
- HTML: `board_report`는 `decision_summary` 누락 시 별도 경고, `strategy_brief`는 explicit decision block 누락 시 별도 경고
|
||||
- HTML 품질 계산 시 `h2`만이 아니라 `board_report`, `strategy_brief`, `comparison`, `roadmap`, `decision_summary`, `evidence_cards`, `kpi`를 `major section`/`supporting block` 추정에 반영
|
||||
- DOCX: 장문 비즈니스 문서에서 evidence table, callout/highlight 부족을 별도 이슈로 판정
|
||||
- XLSX: dashboard workbook의 `trend_series`, `variance_series`, `sheet_summaries`, `dashboard_tiles` 부재를 각각 추가 진단
|
||||
- 보정 가이드 강화:
|
||||
- `ArtifactRepairGuideService.cs`
|
||||
- HTML: board decision summary, strategy brief decision block, comparison/roadmap, evidence-card 보강 가이드 추가
|
||||
- DOCX: evidence table, callout/highlight 보강 가이드 추가
|
||||
- XLSX: trend/variance framing, supporting sheet summary, headline tile, follow-up action 보강 가이드 추가
|
||||
- `DeckRepairGuideService.cs`
|
||||
- Executive Summary의 decision ask, recommendation slide의 rationale/next steps 누락을 별도 액션으로 변환
|
||||
- Workbook review 입력 확장:
|
||||
- `WorkbookReviewInput`에 `HasTrendSection`, `HasVarianceSection`, `HasDashboardTileSection` 추가
|
||||
- `ExcelSkill.cs`의 single-summary/multi-sheet review 경로가 위 신호를 실제 review에 전달
|
||||
- Deck 품질 기준 강화:
|
||||
- `DeckQualityReviewService.cs`
|
||||
- Executive Summary 내 recommendation/decision ask 누락 감지
|
||||
- Recommendation slide의 rationale/next steps 누락 감지
|
||||
- Roadmap slide가 1개 phase만 가진 경우 경고
|
||||
- Golden/회귀 테스트 확장:
|
||||
- `HtmlSkillGoldenReportTests.cs`: `strategy-golden.html` 추가
|
||||
- `PptxSkillGoldenDeckTests.cs`: `pmo-golden.pptx` 추가
|
||||
- `ArtifactQualityReviewServiceTests.cs`, `ArtifactRepairGuideServiceTests.cs`, `DeckQualityReviewServiceTests.cs`, `DeckRepairGuideServiceTests.cs` 회귀 확장
|
||||
- 검증:
|
||||
- `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify_doc_finish_batch\\ -p:IntermediateOutputPath=obj\\verify_doc_finish_batch\\`
|
||||
- `dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter "ArtifactQualityReviewServiceTests|ArtifactRepairGuideServiceTests|DeckQualityReviewServiceTests|DeckRepairGuideServiceTests|HtmlSkillGoldenReportTests|PptxSkillGoldenDeckTests|DocxSkillGoldenDocumentTests|ExcelSkillGoldenWorkbookTests" -p:OutputPath=bin\\verify_doc_finish_batch_tests\\ -p:IntermediateOutputPath=obj\\verify_doc_finish_batch_tests\\`
|
||||
|
||||
@@ -17,6 +17,7 @@ public class ArtifactQualityReviewServiceTests
|
||||
<table><tr><th>Metric</th><th>Value</th></tr><tr><td>NPS</td><td>61</td></tr></table>
|
||||
<div class="comparison-grid"></div>
|
||||
<div class="roadmap-block"></div>
|
||||
<div class="decision-summary"></div>
|
||||
<section class="board-report-panel"></section>
|
||||
<section class="strategy-brief-panel"></section>
|
||||
<h2>Recommendation</h2><p>Recommendation text.</p><p>Action support text.</p>
|
||||
@@ -77,6 +78,9 @@ public class ArtifactQualityReviewServiceTests
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false));
|
||||
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("summary sheet", StringComparison.OrdinalIgnoreCase));
|
||||
@@ -101,11 +105,60 @@ public class ArtifactQualityReviewServiceTests
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true));
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false));
|
||||
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("highlights or actions", StringComparison.OrdinalIgnoreCase));
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("supporting detail sheets", StringComparison.OrdinalIgnoreCase));
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("trend or variance formulas", StringComparison.OrdinalIgnoreCase));
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("KPI, trend, or decision content", StringComparison.OrdinalIgnoreCase));
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("trend or variance framing", StringComparison.OrdinalIgnoreCase));
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("summarize each supporting detail sheet", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReviewHtml_ShouldFlagDecisionGap_ForBoardAndStrategyPanels()
|
||||
{
|
||||
var html =
|
||||
"""
|
||||
<h2>Executive Summary</h2><p>Summary text.</p><p>Supporting paragraph.</p>
|
||||
<section class="board-report-panel"></section>
|
||||
<section class="strategy-brief-panel"></section>
|
||||
<div class="comparison-grid"></div>
|
||||
<div class="roadmap-block"></div>
|
||||
<h2>Recommendation</h2><p>Recommendation text.</p><p>More detail.</p>
|
||||
<h2>Appendix</h2><p>Reference detail.</p><p>More detail.</p>
|
||||
""";
|
||||
|
||||
var review = ArtifactQualityReviewService.ReviewHtml("Decision Gap", html, hasCover: false, hasTableOfContents: false, printReady: true);
|
||||
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("Board-ready report should include a decision summary block", StringComparison.OrdinalIgnoreCase));
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("Strategy brief should include explicit decisions", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReviewStructuredDocument_ShouldRecommendEvidenceTableAndCallouts_ForLongBusinessDoc()
|
||||
{
|
||||
var review = ArtifactQualityReviewService.ReviewStructuredDocument(new StructuredDocumentReviewInput(
|
||||
"Executive Brief",
|
||||
6,
|
||||
2400,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true));
|
||||
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("evidence table", StringComparison.OrdinalIgnoreCase));
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("callout or highlight blocks", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,15 +15,16 @@ public class ArtifactRepairGuideServiceTests
|
||||
["Includes summary sheet"],
|
||||
[
|
||||
new ArtifactReviewIssue("Dashboard sheet lacks KPI, trend, or decision content.", ArtifactReviewSeverity.Info),
|
||||
new ArtifactReviewIssue("Workbook could benefit from a dashboard sheet to summarize multi-sheet trends.", ArtifactReviewSeverity.Info),
|
||||
new ArtifactReviewIssue("Summary sheet does not link to detail sheets.", ArtifactReviewSeverity.Warning)
|
||||
new ArtifactReviewIssue("Dashboard sheet lacks trend or variance framing for the supporting sheets.", ArtifactReviewSeverity.Info),
|
||||
new ArtifactReviewIssue("Dashboard workbook should summarize each supporting detail sheet.", ArtifactReviewSeverity.Info)
|
||||
]);
|
||||
|
||||
var guide = ArtifactRepairGuideService.BuildGuide(review);
|
||||
|
||||
guide.Should().Contain("dashboard sheet");
|
||||
guide.Should().Contain("dashboard");
|
||||
guide.Should().Contain("core story");
|
||||
guide.Should().Contain("detail sheets");
|
||||
guide.Should().Contain("trend");
|
||||
guide.Should().Contain("sheet summaries");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -34,14 +35,14 @@ public class ArtifactRepairGuideServiceTests
|
||||
70,
|
||||
["Includes print-ready CSS"],
|
||||
[
|
||||
new ArtifactReviewIssue("Print-ready business report would benefit from decision summary or evidence cards.", ArtifactReviewSeverity.Warning),
|
||||
new ArtifactReviewIssue("Strategy brief would be stronger with a comparison or roadmap block.", ArtifactReviewSeverity.Info)
|
||||
new ArtifactReviewIssue("Board-ready report should include a decision summary block.", ArtifactReviewSeverity.Warning),
|
||||
new ArtifactReviewIssue("Strategy brief should include explicit decisions or a decision summary block.", ArtifactReviewSeverity.Warning)
|
||||
]);
|
||||
|
||||
var guide = ArtifactRepairGuideService.BuildGuide(review);
|
||||
|
||||
guide.Should().Contain("decision summary");
|
||||
guide.Should().Contain("comparison or roadmap");
|
||||
guide.Should().Contain("strategy brief");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -52,15 +53,15 @@ public class ArtifactRepairGuideServiceTests
|
||||
66,
|
||||
["Includes cover page"],
|
||||
[
|
||||
new ArtifactReviewIssue("Long document could benefit from a table of contents.", ArtifactReviewSeverity.Info),
|
||||
new ArtifactReviewIssue("Template-based styling could improve consistency for a longer document.", ArtifactReviewSeverity.Info),
|
||||
new ArtifactReviewIssue("Supporting evidence table is limited for a business document.", ArtifactReviewSeverity.Info),
|
||||
new ArtifactReviewIssue("Key messages would benefit from callout or highlight blocks.", ArtifactReviewSeverity.Info),
|
||||
new ArtifactReviewIssue("Header or footer metadata is limited for a business document.", ArtifactReviewSeverity.Info)
|
||||
]);
|
||||
|
||||
var guide = ArtifactRepairGuideService.BuildGuide(review);
|
||||
|
||||
guide.Should().Contain("table of contents");
|
||||
guide.Should().Contain("template");
|
||||
guide.Should().Contain("evidence table");
|
||||
guide.Should().Contain("callout");
|
||||
guide.Should().Contain("header and footer");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class DeckQualityReviewServiceTests
|
||||
{ "layout": "title", "title": "Growth Strategy" },
|
||||
{ "layout": "executive_summary", "title": "Executive Summary", "headline": "Headline", "summary_points": ["A","B","C"], "recommendation": "Do B" },
|
||||
{ "layout": "comparison", "title": "Options", "headline": "Compare", "options": [{ "name": "A", "pros": "Fast", "cons": "Shallow", "verdict": "Fastest" }, { "name": "B", "pros": "Balanced", "cons": "Needs alignment", "verdict": "Recommended" }] },
|
||||
{ "layout": "roadmap", "title": "Roadmap", "headline": "Execute in three phases" },
|
||||
{ "layout": "roadmap", "title": "Roadmap", "headline": "Execute in three phases", "phases": [{ "title": "Design", "detail": "Lock scope" }, { "title": "Launch", "detail": "Go live" }] },
|
||||
{ "layout": "recommendation", "title": "Recommendation", "recommendation": "Approve phase-1", "summary_points": ["Reason 1", "Reason 2"] },
|
||||
{ "layout": "table", "title": "Appendix & Evidence", "headers": ["Evidence","Detail"], "rows": [["Metric","Value"]] }
|
||||
]
|
||||
@@ -81,6 +81,7 @@ public class DeckQualityReviewServiceTests
|
||||
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("Slide 2"));
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("headline is too long"));
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("decision ask", StringComparison.OrdinalIgnoreCase));
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("comparison slide needs at least two options"));
|
||||
}
|
||||
|
||||
@@ -107,4 +108,21 @@ public class DeckQualityReviewServiceTests
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("Storyline expects a roadmap slide", StringComparison.OrdinalIgnoreCase));
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("Storyline expects appendix or evidence support", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReviewDeck_ShouldFlagRecommendationSlideWithoutRationaleOrNextSteps()
|
||||
{
|
||||
using var slides = JsonDocument.Parse(
|
||||
"""
|
||||
[
|
||||
{ "layout": "title", "title": "PMO Steering" },
|
||||
{ "layout": "executive_summary", "title": "Executive Summary", "headline": "Delivery is stable", "summary_points": ["A", "B"], "recommendation": "Proceed" },
|
||||
{ "layout": "recommendation", "title": "Recommendation", "recommendation": "Proceed" }
|
||||
]
|
||||
""");
|
||||
|
||||
var review = DeckQualityReviewService.ReviewDeck("Thin Recommendation", slides.RootElement, hasTemplate: false, autoRepairCount: 0);
|
||||
|
||||
review.Issues.Should().Contain(issue => issue.Message.Contains("supporting rationale or next steps", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,4 +70,22 @@ public class DeckRepairGuideServiceTests
|
||||
guide.Should().Contain("comparison slide");
|
||||
guide.Should().Contain("storyline");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildGuide_ShouldTranslateDecisionAskAndNextStepGaps()
|
||||
{
|
||||
var report = new DeckQualityReport(
|
||||
60,
|
||||
[],
|
||||
[
|
||||
new DeckReviewIssue("Slide 2: Executive Summary should include a recommendation or decision ask.", DeckReviewSeverity.Info),
|
||||
new DeckReviewIssue("Slide 3: recommendation slide needs supporting rationale or next steps.", DeckReviewSeverity.Info)
|
||||
],
|
||||
[]);
|
||||
|
||||
var guide = DeckRepairGuideService.BuildGuide(report);
|
||||
|
||||
guide.Should().Contain("decision ask");
|
||||
guide.Should().Contain("next steps");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,4 +142,121 @@ public class HtmlSkillGoldenReportTests
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_WithStrongStrategyBrief_ShouldReturnStableQualitySummary()
|
||||
{
|
||||
var workDir = Path.Combine(Path.GetTempPath(), "ax-html-golden-strategy-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(workDir);
|
||||
|
||||
try
|
||||
{
|
||||
var tool = new HtmlSkill();
|
||||
var context = new AgentContext
|
||||
{
|
||||
WorkFolder = workDir,
|
||||
Permission = "Auto",
|
||||
OperationMode = "external",
|
||||
};
|
||||
|
||||
var args = JsonDocument.Parse(
|
||||
"""
|
||||
{
|
||||
"path": "strategy-golden.html",
|
||||
"title": "Growth Strategy Brief",
|
||||
"body": "",
|
||||
"toc": true,
|
||||
"print": true,
|
||||
"cover": {
|
||||
"title": "Growth Strategy Brief",
|
||||
"subtitle": "Decision-ready strategy pack",
|
||||
"author": "AX Copilot",
|
||||
"date": "2026-04-15"
|
||||
},
|
||||
"sections": [
|
||||
{ "type": "heading", "level": 2, "text": "Executive Summary" },
|
||||
{ "type": "paragraph", "text": "The strongest near-term growth path is an SMB-first expansion strategy that protects margin while improving sales velocity. The evidence is consistent across retention, commercial efficiency, and onboarding load." },
|
||||
{ "type": "paragraph", "text": "Leadership should approve the SMB-first sequencing now, then unlock enterprise investment after onboarding capacity stabilizes. This is a sequencing choice, not a strategic reversal." },
|
||||
{
|
||||
"type": "strategy_brief",
|
||||
"title": "Strategic Question",
|
||||
"strategic_question": "Which segment should be prioritized over the next two quarters?",
|
||||
"thesis": "SMB-first expansion offers the best balance of growth, margin, and execution risk.",
|
||||
"implications": [
|
||||
"Commercial resources should shift toward faster-cycle opportunities.",
|
||||
"Enterprise capacity should be staged behind onboarding readiness."
|
||||
],
|
||||
"decisions": [
|
||||
"Approve SMB-first sequencing",
|
||||
"Stage enterprise hiring after week 8"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "comparison",
|
||||
"title": "Strategic Options",
|
||||
"items": [
|
||||
{ "name": "SMB first", "summary": "Fastest near-term growth", "pros": "Strong retention and shorter sales cycle", "cons": "Smaller average deal size", "verdict": "Recommended" },
|
||||
{ "name": "Balanced mix", "summary": "Diversified growth path", "pros": "Lower concentration risk", "cons": "More operating complexity", "verdict": "Balanced" },
|
||||
{ "name": "Enterprise first", "summary": "Highest headline upside", "pros": "Largest deal size", "cons": "Longest ramp and heaviest onboarding load", "verdict": "Long-term option" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "evidence_cards",
|
||||
"title": "Evidence",
|
||||
"items": [
|
||||
{ "title": "Retention", "detail": "SMB retention remains above plan across the last three cohorts.", "source": "Revenue analytics", "tag": "KPI" },
|
||||
{ "title": "Onboarding load", "detail": "Enterprise onboarding is the main delivery bottleneck.", "source": "Operations review", "tag": "Ops" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "roadmap",
|
||||
"title": "Execution Roadmap",
|
||||
"phases": [
|
||||
{ "title": "Refocus", "detail": "Reset segment priorities and revenue targets", "timeline": "Weeks 1-2", "owner": "Strategy" },
|
||||
{ "title": "Enable", "detail": "Align messaging, pricing, and onboarding", "timeline": "Weeks 3-6", "owner": "Sales + Ops" },
|
||||
{ "title": "Scale", "detail": "Expand channel coverage and monitor retention", "timeline": "Weeks 7-12", "owner": "GM" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "decision_summary",
|
||||
"title": "Decision Summary",
|
||||
"decision": "Approve the SMB-first growth plan and stage enterprise investment after onboarding capacity stabilizes.",
|
||||
"rationale": "The SMB-first path captures faster growth with lower delivery complexity.",
|
||||
"actions": [
|
||||
"Reset next-quarter targets",
|
||||
"Lock the SMB enablement backlog",
|
||||
"Review enterprise readiness at week 8"
|
||||
]
|
||||
},
|
||||
{ "type": "heading", "level": 2, "text": "Appendix" },
|
||||
{ "type": "paragraph", "text": "The appendix contains source notes and supporting assumptions behind the growth model. It preserves traceability from the recommended decision to the underlying evidence." }
|
||||
]
|
||||
}
|
||||
""").RootElement;
|
||||
|
||||
var result = await tool.ExecuteAsync(args, context, CancellationToken.None);
|
||||
|
||||
result.Success.Should().BeTrue();
|
||||
result.Output.Should().Contain("Quality score");
|
||||
result.Output.Should().Contain("Needs work: none");
|
||||
result.Output.Should().Contain("Repair guide: none");
|
||||
|
||||
var html = File.ReadAllText(Path.Combine(workDir, "strategy-golden.html"));
|
||||
html.Should().Contain("strategy-brief-panel");
|
||||
html.Should().Contain("decision-summary");
|
||||
html.Should().Contain("comparison-grid");
|
||||
html.Should().Contain("evidence-cards");
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(workDir))
|
||||
Directory.Delete(workDir, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,4 +237,131 @@ public class PptxSkillGoldenDeckTests
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_WithStrongPmoSteeringDeck_ShouldRemainFreeOfSlideAlerts()
|
||||
{
|
||||
var workDir = Path.Combine(Path.GetTempPath(), "ax-pptx-golden-pmo-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(workDir);
|
||||
|
||||
try
|
||||
{
|
||||
var tool = new PptxSkill();
|
||||
var context = new AgentContext
|
||||
{
|
||||
WorkFolder = workDir,
|
||||
Permission = "Auto",
|
||||
OperationMode = "external",
|
||||
};
|
||||
|
||||
var args = JsonDocument.Parse(
|
||||
"""
|
||||
{
|
||||
"path": "pmo-golden.pptx",
|
||||
"theme": "professional",
|
||||
"template_pack": "pmo",
|
||||
"audience": "Transformation steering committee",
|
||||
"objective": "Confirm the phase-2 PMO steering decision",
|
||||
"decision_ask": "Approve the next wave and keep the governance cadence",
|
||||
"storyline": ["Executive Summary", "Issue Tree", "Risk Overview", "Roadmap", "Recommendation", "Appendix"],
|
||||
"slides": [
|
||||
{
|
||||
"layout": "title",
|
||||
"title": "PMO Steering Pack"
|
||||
},
|
||||
{
|
||||
"layout": "executive_summary",
|
||||
"title": "Executive Summary",
|
||||
"headline": "Phase-2 can proceed with controlled delivery risk and a stable governance model.",
|
||||
"summary_points": [
|
||||
"The current PMO cadence already highlights the few issues that matter most for the next wave.",
|
||||
"The major delivery risk is onboarding bottlenecks, not design ambiguity.",
|
||||
"The decision is now about release timing and governance discipline."
|
||||
],
|
||||
"recommendation": "Approve the next wave and keep the PMO steering cadence intact.",
|
||||
"kpis": [
|
||||
{ "label": "Milestone Health", "value": "92%", "trend": "on track", "note": "core plan stable" },
|
||||
{ "label": "Risk Closure", "value": "78%", "trend": "improving", "note": "weekly review" },
|
||||
{ "label": "Budget", "value": "98%", "trend": "plan", "note": "within guardrails" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "issue_tree",
|
||||
"title": "Issue Tree",
|
||||
"issues": [
|
||||
"Onboarding capacity is the main delivery bottleneck.",
|
||||
"Regional readiness varies by manager capability.",
|
||||
"Decision latency increases when risk owners are unclear."
|
||||
],
|
||||
"implications": [
|
||||
"Protect the launch window with tighter staffing rules.",
|
||||
"Keep manager enablement inside the PMO workplan.",
|
||||
"Confirm named owners for the top-three risk items."
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "risk_heatmap",
|
||||
"title": "Risk Overview",
|
||||
"risks": [
|
||||
{ "title": "Onboarding bottleneck", "impact": "High", "likelihood": "Medium", "mitigation": "Stage wave-2 staffing" },
|
||||
{ "title": "Regional readiness gap", "impact": "Medium", "likelihood": "Medium", "mitigation": "Run manager enablement" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "roadmap",
|
||||
"title": "Roadmap",
|
||||
"headline": "Run the next wave through three controlled PMO checkpoints.",
|
||||
"phases": [
|
||||
{ "title": "Approve", "detail": "Lock funding, risk owners, and wave scope", "timeline": "Week 1", "owner": "SteerCo" },
|
||||
{ "title": "Launch", "detail": "Start the next wave and monitor onboarding load", "timeline": "Weeks 2-6", "owner": "PMO" },
|
||||
{ "title": "Review", "detail": "Confirm milestone health and risk closure", "timeline": "Week 8", "owner": "Exec sponsors" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "recommendation",
|
||||
"title": "Recommendation",
|
||||
"headline": "Approve the next wave and keep governance cadence intact.",
|
||||
"recommendation": "Approve the next wave, keep weekly PMO reviews, and assign named owners to the top-three risks.",
|
||||
"summary_points": [
|
||||
"The current evidence is sufficient to proceed without delaying the launch window.",
|
||||
"Governance continuity is the main control lever for delivery quality."
|
||||
],
|
||||
"next_steps": [
|
||||
"Approve funding and scope",
|
||||
"Confirm risk owners",
|
||||
"Start weekly PMO review for wave 2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"layout": "appendix_evidence",
|
||||
"title": "Appendix & Evidence",
|
||||
"evidence": [
|
||||
{ "title": "Milestone trend", "detail": "Core milestones remain above 90% health", "source": "PMO tracker" },
|
||||
{ "title": "Budget status", "detail": "Program remains inside the approved guardrails", "source": "Finance review" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
""").RootElement;
|
||||
|
||||
var result = await tool.ExecuteAsync(args, context, CancellationToken.None);
|
||||
|
||||
result.Success.Should().BeTrue();
|
||||
File.Exists(Path.Combine(workDir, "pmo-golden.pptx")).Should().BeTrue();
|
||||
result.Output.Should().Contain("PPT quality");
|
||||
result.Output.Should().NotContain("Slide alerts:");
|
||||
result.Output.Should().Contain("Needs work: none");
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(workDir))
|
||||
Directory.Delete(workDir, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,10 @@ public sealed record WorkbookReviewInput(
|
||||
bool HasActionSection,
|
||||
bool HasScorecardSection,
|
||||
bool HasDecisionSection,
|
||||
bool HasSheetSummarySection);
|
||||
bool HasSheetSummarySection,
|
||||
bool HasTrendSection,
|
||||
bool HasVarianceSection,
|
||||
bool HasDashboardTileSection);
|
||||
|
||||
public static class ArtifactQualityReviewService
|
||||
{
|
||||
@@ -131,13 +134,33 @@ public static class ArtifactQualityReviewService
|
||||
var boardPanelCount = Regex.Matches(html, @"board-report-panel", RegexOptions.IgnoreCase).Count;
|
||||
var strategyBriefCount = Regex.Matches(html, @"strategy-brief-panel", RegexOptions.IgnoreCase).Count;
|
||||
var kpiCount = Regex.Matches(html, @"kpi-card|kpi-grid|metric-card", RegexOptions.IgnoreCase).Count;
|
||||
var majorSectionEstimate = sectionCount
|
||||
+ (boardPanelCount > 0 ? 1 : 0)
|
||||
+ (strategyBriefCount > 0 ? 1 : 0)
|
||||
+ (comparisonCount > 0 ? 1 : 0)
|
||||
+ (roadmapCount > 0 ? 1 : 0)
|
||||
+ (matrixCount > 0 ? 1 : 0)
|
||||
+ (decisionCount > 0 ? 1 : 0)
|
||||
+ (evidenceCardCount > 0 ? 1 : 0)
|
||||
+ (kpiCount > 0 ? 1 : 0);
|
||||
var supportingBlockEstimate = paragraphCount
|
||||
+ tableCount
|
||||
+ calloutCount
|
||||
+ comparisonCount
|
||||
+ roadmapCount
|
||||
+ matrixCount
|
||||
+ decisionCount
|
||||
+ evidenceCardCount
|
||||
+ boardPanelCount
|
||||
+ strategyBriefCount
|
||||
+ (kpiCount > 0 ? 1 : 0);
|
||||
var placeholderCount = CountPlaceholders(html);
|
||||
|
||||
if (hasCover) strengths.Add("Includes cover page");
|
||||
if (hasTableOfContents) strengths.Add("Includes table of contents");
|
||||
if (printReady) strengths.Add("Includes print-ready CSS");
|
||||
if (hasPrintFrame) strengths.Add("Includes print header/footer frame");
|
||||
if (sectionCount >= 5) strengths.Add($"Contains {sectionCount} major sections");
|
||||
if (majorSectionEstimate >= 5) strengths.Add($"Contains {majorSectionEstimate} major sections");
|
||||
if (tableCount > 0 || comparisonCount > 0 || roadmapCount > 0 || matrixCount > 0 || decisionCount > 0 || evidenceCardCount > 0 || boardPanelCount > 0 || strategyBriefCount > 0 || kpiCount > 0)
|
||||
strengths.Add("Uses structured business blocks");
|
||||
if (calloutCount > 0) strengths.Add("Uses callout blocks for emphasis");
|
||||
@@ -146,9 +169,9 @@ public static class ArtifactQualityReviewService
|
||||
|
||||
if (html.Length < 1800)
|
||||
issues.Add(new("Body content may be too short for an executive-quality document.", ArtifactReviewSeverity.Warning));
|
||||
if (sectionCount < 4)
|
||||
if (majorSectionEstimate < 4)
|
||||
issues.Add(new("Major section count is low for a business report.", ArtifactReviewSeverity.Warning));
|
||||
if (paragraphCount < sectionCount * 2)
|
||||
if (supportingBlockEstimate < Math.Max(4, majorSectionEstimate * 2))
|
||||
issues.Add(new("Several sections may need more supporting paragraphs.", ArtifactReviewSeverity.Warning));
|
||||
if (tableCount + comparisonCount + roadmapCount + matrixCount + decisionCount + evidenceCardCount + boardPanelCount + strategyBriefCount + kpiCount == 0)
|
||||
issues.Add(new("Structured visual blocks are limited.", ArtifactReviewSeverity.Warning));
|
||||
@@ -158,12 +181,16 @@ public static class ArtifactQualityReviewService
|
||||
issues.Add(new("Executive summary or summary section is missing.", ArtifactReviewSeverity.Warning));
|
||||
if (printReady && !hasPrintFrame)
|
||||
issues.Add(new("Print-ready export is missing a print header/footer frame.", ArtifactReviewSeverity.Info));
|
||||
if (printReady && sectionCount >= 4 && decisionCount + evidenceCardCount == 0)
|
||||
if (printReady && majorSectionEstimate >= 4 && decisionCount + evidenceCardCount == 0)
|
||||
issues.Add(new("Print-ready business report would benefit from decision summary or evidence cards.", ArtifactReviewSeverity.Warning));
|
||||
if (printReady && !hasCover && sectionCount >= 5)
|
||||
if (printReady && !hasCover && majorSectionEstimate >= 5)
|
||||
issues.Add(new("Print-ready report could benefit from a cover page.", ArtifactReviewSeverity.Info));
|
||||
if (boardPanelCount > 0 && decisionCount == 0)
|
||||
issues.Add(new("Board-ready report should include a decision summary block.", ArtifactReviewSeverity.Warning));
|
||||
if (boardPanelCount > 0 && evidenceCardCount == 0 && tableCount == 0)
|
||||
issues.Add(new("Board-ready report would benefit from evidence cards or a supporting table.", ArtifactReviewSeverity.Info));
|
||||
if (strategyBriefCount > 0 && decisionCount == 0)
|
||||
issues.Add(new("Strategy brief should include explicit decisions or a decision summary block.", ArtifactReviewSeverity.Warning));
|
||||
if (strategyBriefCount > 0 && comparisonCount + roadmapCount == 0)
|
||||
issues.Add(new("Strategy brief would be stronger with a comparison or roadmap block.", ArtifactReviewSeverity.Info));
|
||||
|
||||
@@ -202,6 +229,10 @@ public static class ArtifactQualityReviewService
|
||||
issues.Add(new("Recommendation or next-step section is missing.", ArtifactReviewSeverity.Warning));
|
||||
if (input.SectionCount >= 6 && !input.HasAppendixSection)
|
||||
issues.Add(new("Appendix or reference section is limited for a long document.", ArtifactReviewSeverity.Info));
|
||||
if (input.SectionCount >= 5 && input.TableCount == 0)
|
||||
issues.Add(new("Supporting evidence table is limited for a business document.", ArtifactReviewSeverity.Info));
|
||||
if (input.SectionCount >= 5 && input.CalloutCount + input.HighlightCount == 0)
|
||||
issues.Add(new("Key messages would benefit from callout or highlight blocks.", ArtifactReviewSeverity.Info));
|
||||
if (input.TableCount + input.ListCount + input.CalloutCount + input.HighlightCount == 0)
|
||||
issues.Add(new("Document structure is mostly plain paragraphs.", ArtifactReviewSeverity.Warning));
|
||||
|
||||
@@ -248,6 +279,14 @@ public static class ArtifactQualityReviewService
|
||||
issues.Add(new("Dashboard sheet should link to supporting detail sheets.", ArtifactReviewSeverity.Info));
|
||||
if (input.HasDashboardSheet && input.DetailSheetCount >= 2 && input.FormulaCount < 3)
|
||||
issues.Add(new("Dashboard sheet would benefit from more calculated trend or variance formulas.", ArtifactReviewSeverity.Info));
|
||||
if (input.HasDashboardSheet && input.DetailSheetCount >= 2 && !input.HasTrendSection && !input.HasVarianceSection)
|
||||
issues.Add(new("Dashboard sheet lacks trend or variance framing for the supporting sheets.", ArtifactReviewSeverity.Info));
|
||||
if (input.HasDashboardSheet && input.DetailSheetCount >= 2 && !input.HasSheetSummarySection)
|
||||
issues.Add(new("Dashboard workbook should summarize each supporting detail sheet.", ArtifactReviewSeverity.Info));
|
||||
if (input.HasDecisionSection && !input.HasActionSection)
|
||||
issues.Add(new("Decision summary is present but follow-up actions are limited.", ArtifactReviewSeverity.Info));
|
||||
if (input.HasDashboardSheet && !input.HasDashboardTileSection && !input.HasHighlightSection)
|
||||
issues.Add(new("Dashboard sheet would benefit from headline tiles or highlight callouts.", ArtifactReviewSeverity.Info));
|
||||
|
||||
return BuildReport("xlsx", strengths, issues);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,12 @@ public static class ArtifactRepairGuideService
|
||||
|
||||
private static string? BuildHtmlAction(string message)
|
||||
{
|
||||
if (message.Contains("Board-ready report should include a decision summary block", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add a decision summary block directly after the board ask so the approval point is explicit";
|
||||
if (message.Contains("decision summary or evidence cards", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add a decision summary and evidence cards near the recommendation section";
|
||||
if (message.Contains("Strategy brief should include explicit decisions", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add an explicit decisions block or decision summary to the strategy brief";
|
||||
if (message.Contains("cover page", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add a cover page for print-ready or board-facing reports";
|
||||
if (message.Contains("table of contents", StringComparison.OrdinalIgnoreCase))
|
||||
@@ -57,14 +61,22 @@ public static class ArtifactRepairGuideService
|
||||
return "Add KPI, trend, or decision blocks so the dashboard communicates the core story at a glance";
|
||||
if (message.Contains("dashboard sheet", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add a dashboard sheet with KPI tiles, trends, and links to detail sheets";
|
||||
if (message.Contains("trend or variance framing", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add trend and variance blocks so the dashboard explains what changed across the detail sheets";
|
||||
if (message.Contains("summarize each supporting detail sheet", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add sheet summaries so each detail tab rolls up into the dashboard story";
|
||||
if (message.Contains("Summary sheet could better surface", StringComparison.OrdinalIgnoreCase))
|
||||
return "Promote KPIs, decisions, and highlights into the summary or dashboard sheet";
|
||||
if (message.Contains("Dashboard sheet could better call out highlights or actions", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add highlight and action callout blocks to the dashboard sheet";
|
||||
if (message.Contains("headline tiles or highlight callouts", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add dashboard tiles or highlight callouts to surface the top-line business message";
|
||||
if (message.Contains("Dashboard sheet should link", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add hyperlinks from the dashboard to each supporting detail sheet";
|
||||
if (message.Contains("trend or variance formulas", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add trend, variance, or rollup formulas so the dashboard summarizes detail sheets";
|
||||
if (message.Contains("follow-up actions are limited", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add explicit follow-up actions so each dashboard decision has a named next step";
|
||||
if (message.Contains("data validation", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add data validation rules for editable status, owner, or category columns";
|
||||
if (message.Contains("Conditional formatting", StringComparison.OrdinalIgnoreCase))
|
||||
@@ -92,6 +104,10 @@ public static class ArtifactRepairGuideService
|
||||
return "Add a recommendation or next-step section with a clear decision ask";
|
||||
if (message.Contains("Appendix", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add an appendix or reference section for longer documents";
|
||||
if (message.Contains("evidence table", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add at least one supporting evidence table so key claims are traceable";
|
||||
if (message.Contains("callout or highlight blocks", StringComparison.OrdinalIgnoreCase))
|
||||
return "Add callout or highlight blocks to surface the most important messages";
|
||||
if (message.Contains("mostly plain paragraphs", StringComparison.OrdinalIgnoreCase))
|
||||
return "Introduce tables, lists, or callout blocks to break up dense prose";
|
||||
if (message.Contains("too short", StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
@@ -207,6 +207,11 @@ public static class DeckQualityReviewService
|
||||
issues.Add(new($"Slide {slideNumber}: Executive Summary needs more supporting points.", DeckReviewSeverity.Warning));
|
||||
added++;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(ReadString(slide, "recommendation")))
|
||||
{
|
||||
issues.Add(new($"Slide {slideNumber}: Executive Summary should include a recommendation or decision ask.", DeckReviewSeverity.Info));
|
||||
added++;
|
||||
}
|
||||
break;
|
||||
case "recommendation":
|
||||
if (string.IsNullOrWhiteSpace(ReadString(slide, "recommendation")))
|
||||
@@ -214,6 +219,12 @@ public static class DeckQualityReviewService
|
||||
issues.Add(new($"Slide {slideNumber}: recommendation text is missing.", DeckReviewSeverity.Warning));
|
||||
added++;
|
||||
}
|
||||
if (ReadStringList(slide, "summary_points").Count == 0 &&
|
||||
ReadStringList(slide, "next_steps").Count == 0)
|
||||
{
|
||||
issues.Add(new($"Slide {slideNumber}: recommendation slide needs supporting rationale or next steps.", DeckReviewSeverity.Info));
|
||||
added++;
|
||||
}
|
||||
break;
|
||||
case "comparison":
|
||||
if (ReadJsonArrayCount(slide, "options") < 2)
|
||||
@@ -228,6 +239,11 @@ public static class DeckQualityReviewService
|
||||
issues.Add(new($"Slide {slideNumber}: roadmap slide is missing phases.", DeckReviewSeverity.Warning));
|
||||
added++;
|
||||
}
|
||||
else if (ReadJsonArrayCount(slide, "phases") < 2)
|
||||
{
|
||||
issues.Add(new($"Slide {slideNumber}: roadmap slide should show at least two phases.", DeckReviewSeverity.Info));
|
||||
added++;
|
||||
}
|
||||
break;
|
||||
case "chart":
|
||||
if (ReadJsonArrayCount(slide, "chart_labels") == 0 || ReadJsonArrayCount(slide, "chart_values") == 0)
|
||||
|
||||
@@ -12,8 +12,12 @@ public static class DeckRepairGuideService
|
||||
{
|
||||
var action = issue.Message switch
|
||||
{
|
||||
var message when message.Contains("decision ask", StringComparison.OrdinalIgnoreCase)
|
||||
=> "Add a recommendation or decision ask directly to the Executive Summary",
|
||||
var message when message.Contains("Executive Summary", StringComparison.OrdinalIgnoreCase)
|
||||
=> "Add or strengthen the Executive Summary with 2-3 evidence-backed takeaways",
|
||||
var message when message.Contains("supporting rationale or next steps", StringComparison.OrdinalIgnoreCase)
|
||||
=> "Add supporting rationale or next steps so the recommendation turns into action",
|
||||
var message when message.Contains("Recommendation", StringComparison.OrdinalIgnoreCase)
|
||||
=> "Add a clear recommendation or decision request slide near the end of the deck",
|
||||
var message when message.Contains("roadmap", StringComparison.OrdinalIgnoreCase)
|
||||
|
||||
@@ -221,6 +221,9 @@ public class ExcelSkill : IAgentTool
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false));
|
||||
foreach (var line in ArtifactQualityOutputFormatter.BuildLines(review))
|
||||
features += $"\n{line}";
|
||||
@@ -332,7 +335,10 @@ public class ExcelSkill : IAgentTool
|
||||
HasSummaryItems(summarySheet, "actions"),
|
||||
HasSummaryItems(summarySheet, "scorecards") || HasSummaryItems(summarySheet, "cards") || HasSummaryItems(summarySheet, "kpis") || HasSummaryItems(summarySheet, "trend_series") || HasSummaryItems(summarySheet, "dashboard_tiles") || HasSummaryItems(summarySheet, "variance_series"),
|
||||
HasStructuredSummaryContent(summarySheet, "decision_summary"),
|
||||
HasSummaryItems(summarySheet, "sheet_summaries")));
|
||||
HasSummaryItems(summarySheet, "sheet_summaries"),
|
||||
HasSummaryItems(summarySheet, "trend_series"),
|
||||
HasSummaryItems(summarySheet, "variance_series"),
|
||||
HasSummaryItems(summarySheet, "dashboard_tiles")));
|
||||
foreach (var line in ArtifactQualityOutputFormatter.BuildLines(review))
|
||||
features += $"\n{line}";
|
||||
|
||||
@@ -477,7 +483,10 @@ public class ExcelSkill : IAgentTool
|
||||
HasSummaryItems(summarySheet, "actions"),
|
||||
HasSummaryItems(summarySheet, "scorecards") || HasSummaryItems(summarySheet, "cards") || HasSummaryItems(summarySheet, "kpis") || HasSummaryItems(summarySheet, "trend_series") || HasSummaryItems(summarySheet, "dashboard_tiles") || HasSummaryItems(summarySheet, "variance_series"),
|
||||
HasStructuredSummaryContent(summarySheet, "decision_summary"),
|
||||
HasSummaryItems(summarySheet, "sheet_summaries")));
|
||||
HasSummaryItems(summarySheet, "sheet_summaries"),
|
||||
HasSummaryItems(summarySheet, "trend_series"),
|
||||
HasSummaryItems(summarySheet, "variance_series"),
|
||||
HasSummaryItems(summarySheet, "dashboard_tiles")));
|
||||
var outputLines = new List<string>
|
||||
{
|
||||
$"Excel 파일 생성 완료: {fullPath}",
|
||||
|
||||
Reference in New Issue
Block a user