- 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\
368 lines
18 KiB
C#
368 lines
18 KiB
C#
using System.IO;
|
|
using System.Text.Json;
|
|
using AxCopilot.Services.Agent;
|
|
using FluentAssertions;
|
|
using Xunit;
|
|
|
|
namespace AxCopilot.Tests.Services;
|
|
|
|
public class PptxSkillGoldenDeckTests
|
|
{
|
|
[Fact]
|
|
public async Task ExecuteAsync_WithStrongBoardDeck_ShouldReturnStableQualitySummary()
|
|
{
|
|
var workDir = Path.Combine(Path.GetTempPath(), "ax-pptx-golden-" + 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": "board-golden.pptx",
|
|
"theme": "professional",
|
|
"audience": "Executive committee",
|
|
"objective": "Approve the phase-1 operating model rollout",
|
|
"decision_ask": "Approve the phase-1 rollout and funding release",
|
|
"slides": [
|
|
{
|
|
"layout": "title",
|
|
"title": "Operating Model Refresh"
|
|
},
|
|
{
|
|
"layout": "executive_summary",
|
|
"title": "Executive Summary",
|
|
"headline": "Phase-1 rollout can improve service consistency while protecting margin.",
|
|
"summary_points": [
|
|
"Three pilot functions account for most process variation and rework.",
|
|
"Phase-1 can be delivered without slowing current-quarter commitments.",
|
|
"The operating model change is expected to reduce handoff delay by 18%."
|
|
],
|
|
"recommendation": "Approve the phase-1 rollout and lock the pilot governance model.",
|
|
"kpis": [
|
|
{ "label": "Cycle Time", "value": "-18%", "trend": "target", "note": "handoff simplification" },
|
|
{ "label": "Margin", "value": "+2.4pt", "trend": "run-rate", "note": "mix and rework" },
|
|
{ "label": "On-time Delivery", "value": "96%", "trend": "pilot", "note": "stable" }
|
|
]
|
|
},
|
|
{
|
|
"layout": "comparison",
|
|
"title": "Options",
|
|
"headline": "A phased rollout balances speed, control, and adoption risk.",
|
|
"options": [
|
|
{ "name": "Pilot only", "pros": "Lowest delivery risk", "cons": "Value capture is delayed", "verdict": "Too cautious" },
|
|
{ "name": "Phased rollout", "pros": "Balanced speed and control", "cons": "Requires PMO discipline", "verdict": "Recommended" },
|
|
{ "name": "Full rollout", "pros": "Fastest value capture", "cons": "High adoption risk", "verdict": "Too disruptive" }
|
|
]
|
|
},
|
|
{
|
|
"layout": "roadmap",
|
|
"title": "Roadmap",
|
|
"headline": "Roll out in three waves with explicit governance checkpoints.",
|
|
"phases": [
|
|
{ "title": "Design", "detail": "Finalize scope, KPIs, and governance", "timeline": "Weeks 1-3", "owner": "PMO" },
|
|
{ "title": "Pilot", "detail": "Launch pilot functions and refine playbooks", "timeline": "Weeks 4-8", "owner": "Operations" },
|
|
{ "title": "Scale", "detail": "Expand to the remaining regions", "timeline": "Weeks 9-14", "owner": "Business" }
|
|
]
|
|
},
|
|
{
|
|
"layout": "recommendation",
|
|
"title": "Recommendation",
|
|
"recommendation": "Approve phase-1 rollout, assign PMO governance, and release pilot funding.",
|
|
"summary_points": [
|
|
"The phased path protects execution quality while capturing measurable value in-quarter.",
|
|
"The pilot governance model can be reused for the scale phase.",
|
|
"The decision can be taken now because the key delivery risks are already bounded."
|
|
],
|
|
"next_steps": [
|
|
"Confirm phase-1 scope this week",
|
|
"Launch pilot governance cadence next week",
|
|
"Review pilot performance at week 8"
|
|
]
|
|
},
|
|
{
|
|
"layout": "table",
|
|
"title": "Appendix & Evidence",
|
|
"headers": ["Evidence", "Detail"],
|
|
"rows": [
|
|
["Process review", "Pilot teams show the highest rework and handoff load."],
|
|
["Financial impact", "Run-rate margin lift is driven by lower rework and better prioritization."]
|
|
]
|
|
}
|
|
]
|
|
}
|
|
""").RootElement;
|
|
|
|
var result = await tool.ExecuteAsync(args, context, CancellationToken.None);
|
|
|
|
result.Success.Should().BeTrue();
|
|
File.Exists(Path.Combine(workDir, "board-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
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ExecuteAsync_WithStrongStrategyDeck_ShouldRemainFreeOfSlideAlerts()
|
|
{
|
|
var workDir = Path.Combine(Path.GetTempPath(), "ax-pptx-golden-strategy-" + 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": "strategy-golden.pptx",
|
|
"theme": "professional",
|
|
"audience": "CEO staff",
|
|
"objective": "Confirm the next-phase growth strategy",
|
|
"decision_ask": "Approve the SMB-first expansion plan",
|
|
"storyline": ["Executive Summary", "Current State", "Options", "Roadmap", "Recommendation", "Appendix"],
|
|
"slides": [
|
|
{
|
|
"layout": "title",
|
|
"title": "Growth Strategy Refresh"
|
|
},
|
|
{
|
|
"layout": "executive_summary",
|
|
"title": "Executive Summary",
|
|
"headline": "An SMB-first strategy gives the best balance of growth, margin, and execution risk.",
|
|
"summary_points": [
|
|
"The SMB segment now drives the strongest retention and the fastest sales cycle.",
|
|
"Enterprise expansion remains attractive but requires heavier onboarding capacity.",
|
|
"The SMB-first path improves near-term growth while keeping operating complexity in bounds."
|
|
],
|
|
"recommendation": "Prioritize SMB expansion, stage enterprise enablement, and re-sequence hiring.",
|
|
"kpis": [
|
|
{ "label": "Growth", "value": "+14%", "trend": "run-rate", "note": "SMB mix" },
|
|
{ "label": "Margin", "value": "+1.8pt", "trend": "plan", "note": "lower service load" },
|
|
{ "label": "Retention", "value": "92%", "trend": "SMB", "note": "stable" }
|
|
]
|
|
},
|
|
{
|
|
"layout": "comparison",
|
|
"title": "Strategic Options",
|
|
"headline": "SMB-first is the strongest near-term path while preserving the enterprise option.",
|
|
"options": [
|
|
{ "name": "SMB first", "pros": "Fast cycle and strong retention", "cons": "Smaller deal size", "verdict": "Recommended" },
|
|
{ "name": "Balanced mix", "pros": "Diversified growth", "cons": "Higher delivery complexity", "verdict": "Balanced" },
|
|
{ "name": "Enterprise first", "pros": "Largest upside", "cons": "Slowest ramp and highest risk", "verdict": "Long-term only" }
|
|
]
|
|
},
|
|
{
|
|
"layout": "roadmap",
|
|
"title": "Execution Roadmap",
|
|
"headline": "Deliver in three phases with clear commercial and delivery checkpoints.",
|
|
"phases": [
|
|
{ "title": "Focus", "detail": "Reset segment priorities and targets", "timeline": "Weeks 1-2", "owner": "Strategy" },
|
|
{ "title": "Enable", "detail": "Align pricing, messaging, and onboarding", "timeline": "Weeks 3-6", "owner": "Sales + Ops" },
|
|
{ "title": "Scale", "detail": "Expand channel coverage and monitor retention", "timeline": "Weeks 7-12", "owner": "GM" }
|
|
]
|
|
},
|
|
{
|
|
"layout": "recommendation",
|
|
"title": "Recommendation",
|
|
"headline": "Approve the SMB-first plan and stage enterprise investment after week 8.",
|
|
"recommendation": "Approve the SMB-first growth plan and stage enterprise investments after onboarding capacity stabilizes.",
|
|
"summary_points": [
|
|
"This path captures the highest near-term growth with the cleanest operating model.",
|
|
"It keeps the enterprise option open without overloading delivery teams.",
|
|
"The required decision is sequencing, not strategic direction."
|
|
],
|
|
"next_steps": [
|
|
"Reset next-quarter targets",
|
|
"Lock SMB enablement backlog",
|
|
"Review enterprise readiness after week 8"
|
|
]
|
|
},
|
|
{
|
|
"layout": "table",
|
|
"title": "Appendix & Evidence",
|
|
"headers": ["Observation", "Implication"],
|
|
"rows": [
|
|
["Retention pattern", "SMB cohort retention is consistently above plan."],
|
|
["Onboarding load", "Enterprise onboarding is the main delivery constraint."]
|
|
]
|
|
}
|
|
]
|
|
}
|
|
""").RootElement;
|
|
|
|
var result = await tool.ExecuteAsync(args, context, CancellationToken.None);
|
|
|
|
result.Success.Should().BeTrue();
|
|
File.Exists(Path.Combine(workDir, "strategy-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
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
[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
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|