diff --git a/docs/decisions.md b/docs/decisions.md index 22de730..1b3d829 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -694,3 +694,25 @@ - 治理字典使用软删除或使用中禁止硬删,变更必须写审计。 **理由**:适配器把协作治理模块的权限和审计接入点收束在一层,既能复用 V2.5 的服务端控制面,也给后续 JWT/NextAuth 和企业级角色体系留下替换点。稳定事件名和多态评论引用能避免后续模块继续扩散 ad-hoc 字段。 + +## 53. Business Analysis Agent 采用语义层、指标目录和受控分析计划 + +**问题**:下一阶段需要让用户用自然语言围绕产品、项目、版本、需求、部门和用户多维度提问,并自动生成图表与分析报告。如果只做“问题 -> 固定模板 -> 查询”,后续会被模板数量卡住;如果让 AI 直接决定查询或生成 ECharts option,则会带来权限绕过、口径不一致、不可复现和难以维护的问题。 + +**决策**: +- 新增独立 Business Analysis Agent,只读业务数据,不修改任何业务实体、不创建草案、不触发状态流转。 +- 自然语言先进入 Semantic Layer,把“忙 / 压力 / 风险 / 延期 / 效率 / 质量 / 需求完成”等业务说法映射到受控 `metricId`、`dimensionId`、`analysisType`、`timeIntent` 和 `scopeIntent`。 +- Semantic Layer 输出内部 `semanticConfidence`;前端只展示高/中/低置信,不展示伪精确百分比。数据充分性另用 `dataConfidence` 表达。 +- 建立 Metric Catalog,记录 metric `version`、公式、owner、支持维度、支持分析类型、默认图表、默认维度和默认时间口径。只要公式或计算口径变更,就提升 metric version;纯展示变化不升版本。 +- 分析策略分三层:Template Strategy 优先命中高频模板;Rule Composition Strategy 是确定性系统规则组合;AI Planning Strategy 只在前两者无法覆盖时生成 `AnalysisPlan` 建议。 +- AI 生成的 `AnalysisPlan` 必须只使用 Semantic Layer / Metric Catalog 暴露的指标、维度、筛选和聚合能力,并经过 Analysis Plan Processor 校验与规范化后才能执行。 +- Analysis Plan Processor 不只校验,也负责 Normalize,将模板、规则组合和 AI proposal 统一成标准 `AnalysisPlan`,Metric Engine 只消费统一格式。 +- Metric Engine 输出统一 `MetricResult`。ChartSpec Builder、Insight Engine、Report Builder 和 Follow-up Builder 并行消费同一份 MetricResult,避免图表和报告互相耦合。 +- ChartSpec 是平台统一契约,不是 ECharts option。前端第一版用 ECharts Renderer 渲染,未来可替换为其他图表引擎。 +- Evidence 不是纯 chips,而是可点击数据证据:包含 label、value、sourceDomain 和 drilldown filters。 +- Report 固定为 Summary / Key Findings / Evidence / Suggestions / Data Scope,避免不同分析回答格式漂移。 +- Follow-up 分为 question、drilldown、export。第一版只允许只读追问、明细跳转和导出,不允许创建会议、分配负责人等写操作。 +- 没有数据时走 No Data Strategy:说明请求、范围、缺少的数据和可替代分析,不让 AI 编造解释。 +- 权限红线:Analysis Agent 只能查询当前用户已有权限的数据,自然语言不能扩大范围;无权限时拒绝或返回授权范围内的空结果。 + +**理由**:Semantic Layer 和 Metric Catalog 能把自然语言、业务口径和数据库字段解耦;metric version 和 result snapshot 能支撑历史分析复现;Analysis Plan Processor 保证 AI proposal 不直接变成系统执行;统一 ChartSpec 和 MetricResult 让 ECharts 只是当前 renderer,而不是长期数据契约。这样第一版可以靠固定模板稳定交付,后续又能通过确定性组合和受控 AI Planning 扩展能力。 diff --git a/docs/superpowers/specs/2026-07-08-business-analysis-agent-design.md b/docs/superpowers/specs/2026-07-08-business-analysis-agent-design.md new file mode 100644 index 0000000..aa7e56d --- /dev/null +++ b/docs/superpowers/specs/2026-07-08-business-analysis-agent-design.md @@ -0,0 +1,743 @@ +# Business Analysis Agent Design + +## Goal + +Build a read-only Business Analysis Agent that lets users ask FTB business data questions in natural language and receive an Insight Card, a chart, an analysis report, explainable evidence, and safe follow-up options. + +The first product surface is the AI Assistant business-data conversation. The same analysis engine will also be embedded in product, project, and version detail pages with the current page context pre-filled. + +## Approved Direction + +- Use a dedicated Business Analysis Agent instead of extending Prototype Decompose Agent or Risk Watch Agent. +- Use ECharts as the first chart renderer, but do not expose raw ECharts options as the platform contract. +- Define a platform Unified ChartSpec and render it through a frontend Chart Renderer. +- Use Apple Vision style visual rules: large whitespace, large radius, light shadow, translucent material, clear hierarchy, natural motion, and content-first charts. +- Default to the last 30 days only for time-window analysis when the user did not specify a time range. Current status, risk, and lifecycle questions must use their natural business scope instead of forcing last 30 days. +- Every answer must include a structured report, not only a chart. +- The Agent must not mutate business data, create drafts, change workflow state, or bypass permissions. + +## Non-Goals + +- No AI-generated SQL. +- No direct AI database access. +- No arbitrary dashboard builder in the first implementation. +- No automatic business actions such as creating meetings, assigning owners, or changing due dates. +- No colorful BI big-screen style, 3D effects, dense dashboards, or raw table dumps as the primary answer. +- No new AppData key as a source of truth. + +## Core Architecture + +```text +User question + optional page context + ↓ +Analysis Planner + ↓ +Semantic Layer + ↓ +Permission Scope Resolver + ↓ +Analysis Strategy + 1. Template Strategy + 2. Rule Composition Strategy (Deterministic) + 3. AI Planning Strategy + ↓ +Analysis Plan Processor + - Validate: permission, metric, dimension, aggregation, time range, data scope + - Normalize: produce one standard AnalysisPlan shape + ↓ +Metric Engine + ↓ +Metric Result + ├─ ChartSpec Builder + ├─ Insight Engine + ├─ Report Builder + └─ Follow-up Builder + ↓ +UI Composition + ↓ +Insight Card + Chart + Report + Evidence + Follow-ups +``` + +### Responsibility Boundaries + +- **Analysis Planner** reads the question and current page context, then produces an initial intent. +- **Semantic Layer** maps business words such as "busy", "pressure", "risk", "delay", "efficiency", and "quality" to system-owned metrics and dimensions. +- **Permission Scope Resolver** converts the current user and page context into a queryable scope. It must never widen the user's existing data access. +- **Analysis Strategy** chooses how to build the analysis plan. +- **Analysis Plan Processor** validates and normalizes all plans, including AI-generated ones. +- **Metric Engine** executes deterministic relation-table queries and aggregations. +- **ChartSpec Builder**, **Insight Engine**, **Report Builder**, and **Follow-up Builder** consume the same Metric Result in parallel. +- **UI Composition** assembles the final response for chat and context-page surfaces. + +## Analysis Strategy + +### 1. Template Strategy + +Use fixed high-frequency templates for stable MVP analyses such as requirement completion, version risk, member workload, department workload, and Bug distribution. + +Template Strategy should be preferred whenever the user question cleanly matches a known template. + +### 2. Rule Composition Strategy (Deterministic) + +When no complete template matches, deterministic system rules may compose known semantic concepts, metrics, dimensions, and time policies. + +Example: + +```text +"最近两个月延期原因变化" +→ trend + delay_reason + month + project/version scope +``` + +This composition is not done by AI. It is a rule engine over the Semantic Layer and Metric Catalog. + +### 3. AI Planning Strategy + +When neither template nor deterministic rule composition covers the question, AI may generate an Analysis Plan proposal. + +AI Planning constraints: + +- AI only proposes an Analysis Plan. +- The plan may only use metrics, dimensions, filters, aggregations, and time policies exposed by the Semantic Layer and Metric Catalog. +- The plan must pass Analysis Plan Processor validation and normalization before execution. +- If the plan references an unsupported metric, dimension, aggregation, filter, or scope, the system rejects it and returns a clarification or unsupported-analysis response. + +Enterprise principle: AI does not directly decide what the system executes. AI proposes; the system validates, normalizes, and executes. + +## Semantic Layer + +The Semantic Layer is the business vocabulary boundary between natural language and system metrics. + +### First Semantic Concepts + +| User wording | Semantic concept | Default interpretation | +|---|---|---| +| 忙 / 负载高 | `workload` | Open item count plus estimated or actual effort, with overtime as supporting evidence | +| 压力大 | `work_pressure` | Usually workload plus overdue and overtime; lower semantic confidence than "忙" | +| 风险高 | `release_risk` | Xiaobao summary, blockers, bugs, test completion, remaining time | +| 延期 | `delay` | Past planned end or expected release, or forecast release later than target | +| 效率 | `delivery_efficiency` | Completion volume per effort; fall back to completion trend if effort data is insufficient | +| 质量差 | `quality_risk` | Open bugs, critical bugs, failed cases, blocked cases, repeated test rounds | +| 需求完成 | `requirement_completion` | Requirement status plus version delivery progress | + +### Semantic Confidence + +Semantic parsing must produce an internal `semanticConfidence`. + +- High confidence: direct wording maps clearly to one concept, such as "延期率" → `delay_rate`. +- Medium confidence: wording is common but may carry multiple business meanings, such as "压力最大" → `work_pressure`. +- Low confidence: wording is vague or could map to unrelated metrics. + +UI display should use levels, not pseudo-precise numbers: + +- `high`: proceed directly. +- `medium`: proceed but show the assumed interpretation in Data Scope. +- `low`: ask a clarification or show selectable interpretations. + +Do not display "AI confidence 96%" as a primary user-facing claim. Internal scores may be kept for ranking candidate interpretations. + +## Metric Catalog + +Metric Catalog is the stable source of truth for what the Business Analysis Agent can measure. + +```ts +type MetricId = string; + +type DimensionId = + | 'product' + | 'project' + | 'version' + | 'requirement_status' + | 'requirement_type' + | 'requirement_source' + | 'department' + | 'member' + | 'role' + | 'month' + | 'week' + | 'day' + | 'bug_severity' + | 'bug_status' + | 'test_status' + | 'delay_reason'; + +type AnalysisType = + | 'ranking' + | 'trend' + | 'comparison' + | 'distribution' + | 'composition' + | 'correlation' + | 'breakdown' + | 'summary'; + +type TimePolicy = + | 'current_state' + | 'last_30_days' + | 'lifecycle' + | 'user_required' + | 'explicit_range'; + +type ChartKind = + | 'number_card' + | 'line_area' + | 'horizontal_bar' + | 'stacked_horizontal_bar' + | 'donut' + | 'table_preview'; + +type MetricDefinition = { + metricId: MetricId; + version: number; + name: string; + description: string; + formula: string; + owner: string; + supportedDimensions: DimensionId[]; + supportedAnalysisTypes: AnalysisType[]; + defaultChart: ChartKind; + defaultDimension?: DimensionId; + defaultTimePolicy: TimePolicy; + status: 'active' | 'deprecated'; +}; +``` + +Metric versioning is required. If the formula or business calculation changes, increment `version`. Do not increment the metric version for pure chart styling, copy, or layout changes. + +Metric Result and analysis reports must record: + +```ts +type MetricRef = { + metricId: string; + version: number; +}; +``` + +Historical reproducibility needs both: + +- `metricRef`: which metric algorithm was used. +- `analysisSnapshot` or `resultSnapshot`: the aggregated result at the time, because live business rows may change later. + +## Analysis Plan Processor + +The Analysis Plan Processor replaces a narrow "validator" with a stronger validate-and-normalize boundary. + +Normalized plan shape: + +```ts +type DataScope = + | { type: 'self'; userId: string } + | { type: 'managed_projects'; projectIds: string[] } + | { type: 'product'; productId: string } + | { type: 'project'; projectId: string } + | { type: 'version'; versionId: string } + | { type: 'system'; reason: 'admin' | 'management_permission' }; + +type AnalysisPlan = { + metricRef: MetricRef; + analysisType: AnalysisType; + dimensions: DimensionId[]; + timeRange?: { + start: string; + end: string; + policy: TimePolicy; + }; + filters: Record; + scope: DataScope; + limit?: number; + sort?: Array<{ field: string; direction: 'asc' | 'desc' }>; +}; +``` + +### Validate + +It must check: + +- Current user is allowed to access the requested scope. +- Metric exists and is active. +- Metric version exists or can resolve to current active version. +- Dimensions are supported by the metric. +- Analysis type is supported by the metric. +- Aggregation is legal for the metric and dimension. +- Time range is valid and within supported business bounds. +- Filters are known, typed, and compatible with the scope. +- Requested Top N is within system limits. + +### Normalize + +It converts all strategy outputs into the same `AnalysisPlan` shape. + +Example: + +```ts +// AI or user wording +{ + time: '最近半年', + metric: '延期率' +} + +// normalized +{ + metricRef: { metricId: 'delay_rate', version: 1 }, + analysisType: 'trend', + dimensions: ['month'], + timeRange: { + start: '2026-01-01', + end: '2026-06-30' + }, + filters: {}, + scope: { type: 'user_accessible' }, + limit: 12 +} +``` + +The Metric Engine only accepts normalized `AnalysisPlan`. + +## Time Range Rules + +1. If the user specifies a time range, use that exact range. +2. If the question asks current state or risk, use current state data instead of last 30 days. +3. If the question asks trend, throughput, efficiency, effort, or change and does not specify time, use last 30 days. +4. If the question asks comparison and does not specify a baseline, use last 30 days versus the previous 30 days. +5. If the question asks lifecycle totals, use the object lifecycle. +6. Every response must show the applied time scope, data cutoff time, permission scope, and whether the analysis is current-state, time-window, comparison, or lifecycle. + +## Permissions + +The Business Analysis Agent can only query data the current user can already access. + +First implementation scope: + +- AI Assistant global analysis is available to logged-in users. +- Normal users see only data related to themselves or contexts they can access. +- Users with `management:view`, system admin permissions, or project Owner/Admin governance can analyze their managed scope. +- Product, project, and version detail analysis follows the page's existing access rules and must not widen scope. + +Natural language cannot bypass permission boundaries. If a user asks for a forbidden scope, return a no-permission response or an empty authorized result with clear Data Scope. + +## MVP Analysis Templates + +The MVP starts with fixed templates while preserving the three-layer Analysis Strategy for future flexibility. + +| Group | Template | Default chart | Time policy | Default limit | +|---|---|---|---|---| +| Risk and progress | Version risk ranking | Horizontal bar + numeric card | Current state | Top 10 | +| Risk and progress | Project or version completion trend | Smooth line area | Last 30 days if unspecified | 30 points | +| Risk and progress | Overdue item distribution | Horizontal bar | Current state | Top 10 | +| Product and requirements | Product requirement status distribution | Donut + numeric card | Current state or explicit range | All statuses | +| Product and requirements | Requirement completion trend | Smooth line area | Last 30 days if unspecified | 30 points | +| Product and requirements | Requirement source/type composition | Donut | Last 30 days if unspecified | Top 8 + other | +| People and departments | Department workload ranking | Horizontal bar | Current state | Top 10 | +| People and departments | Member pending-work ranking | Horizontal bar | Current state | Top 10 | +| People and departments | Member effort ranking | Horizontal bar + numeric card | Last 30 days if unspecified | Top 10 | +| Quality | Bug severity distribution | Stacked horizontal bar | Current state | Top 10 | +| Quality | Test pass-rate trend | Smooth line area | Last 30 days if unspecified | 30 points | +| Effort | Overtime reason composition and ranking | Donut + horizontal bar | Last 30 days if unspecified | Top 8 | + +Top N must be explicit in every ranking plan. Default is Top 10. The first implementation should cap user-requested limits to a safe maximum, such as Top 20. + +## Metric Result + +Metric Result is the reusable output of the Metric Engine. Chart, report, insight, export, and future dashboard cards consume this result in parallel. + +```ts +type MetricResult = { + metricRef: MetricRef; + analysisType: AnalysisType; + columns: Array<{ id: string; label: string; type: 'string' | 'number' | 'date' | 'percent' }>; + rows: Array>; + totals?: Record; + comparison?: { + baselineLabel: string; + currentLabel: string; + deltaValue?: number; + deltaPercent?: number; + }; + evidence: EvidenceItem[]; + dataScope: DataScope; + generatedAt: string; +}; +``` + +## Evidence + +Evidence is clickable data proof, not only visual chips. + +```ts +type EvidenceItem = { + label: string; + value: string | number; + unit?: string; + sourceDomain: + | 'product' + | 'project' + | 'version' + | 'requirement' + | 'version_plan' + | 'dev_task' + | 'test_case' + | 'bug' + | 'work_activity' + | 'task_worklog' + | 'overtime' + | 'xiaobao'; + sourceLabel?: string; + drilldown?: { + type: 'list' | 'detail'; + target: string; + filters: Record; + }; +}; +``` + +Examples: + +- `未关闭 Bug / 18 / Bug Domain / click → Bug list filtered by open statuses` +- `阻塞任务 / 6 / DevTask Domain / click → DevTask list filtered by blocked` +- `测试通过率 / 62% / TestCase Domain / click → test case detail list` + +## Unified ChartSpec + +ChartSpec is platform-owned and renderer-agnostic. It is not an ECharts option object. + +```ts +type UnifiedChartSpec = { + kind: ChartKind; + title: string; + subtitle?: string; + dataset: { + source: Array>; + x?: string; + y?: string; + series?: string; + value?: string; + label?: string; + }; + encoding: { + x?: { field: string; label: string }; + y?: { field: string; label: string }; + value?: { field: string; label: string; unit?: string }; + color?: { mode: 'single' | 'risk' | 'semantic'; field?: string }; + }; + annotations?: Array<{ + type: 'outlier' | 'peak' | 'target' | 'threshold'; + label: string; + value?: string | number; + field?: string; + }>; + stylePreset: 'apple_vision_light' | 'apple_vision_dark'; +}; +``` + +Frontend `ChartRenderer` converts Unified ChartSpec into ECharts options. This keeps the contract stable if the renderer changes later. + +## Apple Vision Chart Design System + +### Overall + +- White or deep neutral background. +- Large whitespace and clear hierarchy. +- Large rounded cards, light borders, soft shadows, and translucent material. +- Content first; numbers and conclusions lead the page. +- No blue gradient dashboard, no dense big-screen layout, no rainbow metrics, no 3D shine. + +### Number Cards + +The number is the hero. + +Structure: + +```text +238 +已完成需求 +↑ 12% +较上周期 +``` + +Rules: + +- Big number, small label. +- Comparison line is secondary. +- Risk or negative trend may use orange/red; normal values use a restrained single accent color. + +### Line Charts + +Use Apple Stocks-like style: + +- Smooth curve. +- Subtle area gradient. +- Minimal axes and grid. +- Highlight peaks, drops, or anomaly points automatically. +- Do not draw heavy traditional grid lines. + +### Bar Charts + +Use horizontal bars for ranking: + +```text +研发 ████████ +产品 ██████ +测试 ████ +``` + +Rules: + +- Single color by default. +- Rounded bar caps. +- Soft entrance animation. +- Values aligned for scanning. +- Use Top N; do not render 100 members in one chart. + +### Donut and Composition Charts + +- Use only when part-to-whole composition matters. +- Limit slices to Top 8 plus "其他". +- Use restrained semantic colors. Avoid five-color decoration unless categories need separation. + +### Motion + +- Entrance animation is soft and short. +- Tooltip follows pointer naturally. +- Hover reveals detail without moving layout. +- No dramatic loading animation or distracting particle effects. + +## Insight, Report, and Follow-Ups + +### Insight Card + +Insight Card comes before the chart. It is one concise conclusion, such as: + +```text +产品部延期事项最多,占当前延期事项的 49%。 +``` + +It should include: + +- Main conclusion. +- Main metric value. +- Trend or comparison if available. +- Confidence level if semantic or data confidence is not high. + +```ts +type InsightCard = { + summary: string; + primaryValue?: { + label: string; + value: string | number; + unit?: string; + }; + comparison?: { + label: string; + direction: 'up' | 'down' | 'flat'; + value: string | number; + tone: 'positive' | 'negative' | 'neutral'; + }; + semanticConfidence: 'high' | 'medium' | 'low'; + dataConfidence: 'sufficient' | 'partial' | 'insufficient'; +}; +``` + +### Report Structure + +Reports use a fixed structure: + +1. Summary +2. Key Findings +3. Evidence +4. Suggestions +5. Data Scope + +AI may write the prose, but it must only use Metric Result data, Evidence, and Data Scope. + +```ts +type AnalysisReport = { + summary: string; + keyFindings: string[]; + evidence: EvidenceItem[]; + suggestions: string[]; + dataScope: { + timeDescription: string; + permissionDescription: string; + metricFormulaDescription: string; + generatedAt: string; + }; +}; +``` + +### Follow-Up Types + +```ts +type FollowUp = + | { + type: 'question'; + label: string; + prompt: string; + } + | { + type: 'drilldown'; + label: string; + target: string; + filters: Record; + } + | { + type: 'export'; + label: string; + format: 'png' | 'pdf' | 'csv'; + }; +``` + +First version follow-ups are read-only: + +- Follow-up question: "为什么延期?" +- Drilldown: "查看负责人", "查看 Bug 明细", "切到版本维度" +- Export: "导出分析报告" + +Business-mutating follow-ups such as creating meetings, assigning owners, or changing plans are excluded from the MVP. They require explicit user confirmation and domain API design in a later phase. + +## Data Confidence + +Data confidence is separate from semantic confidence. + +Display levels: + +- `sufficient`: enough rows, current data, reliable plan dates or status facts. +- `partial`: some missing dates, sparse records, or incomplete evidence. +- `insufficient`: no usable rows or too few rows for the requested comparison. + +Examples that lower data confidence: + +- No planned end dates. +- Missing work activities. +- No historical baseline for comparison. +- Small sample size. +- Current user only has partial scope. + +## No Data Strategy + +If there is no data, do not let AI invent an explanation. + +Return a structured no-data result: + +- State what was requested. +- State why no result can be computed. +- Show the applied scope and time range. +- Suggest valid alternatives. + +Example: + +```text +没有找到 2025 年测试通过率数据。 +可以改看 2026 年、当前版本测试完成情况,或按项目查看已有测试用例。 +``` + +## API Shape + +Initial endpoint: + +```text +POST /api/v1/ai/analysis +``` + +Request: + +```ts +type AnalysisRequest = { + question: string; + context?: { + surface: 'ai_assistant' | 'product_detail' | 'project_detail' | 'version_detail'; + productId?: string; + projectId?: string; + versionId?: string; + }; +}; +``` + +Response: + +```ts +type AnalysisResponse = + | { + ok: true; + plan: AnalysisPlan; + metricResult: MetricResult; + insight: InsightCard; + chart: UnifiedChartSpec; + report: AnalysisReport; + followUps: FollowUp[]; + } + | { + ok: false; + code: + | 'NO_PERMISSION' + | 'UNSUPPORTED_ANALYSIS' + | 'AMBIGUOUS_INTENT' + | 'NO_DATA' + | 'AI_UNAVAILABLE' + | 'INVALID_PLAN'; + message: string; + clarificationOptions?: Array<{ label: string; prompt: string }>; + dataScope?: DataScope; + }; +``` + +## Error Handling + +- `NO_PERMISSION`: user asked for a scope outside authorized data. +- `UNSUPPORTED_ANALYSIS`: metric or dimension is not in the catalog. +- `AMBIGUOUS_INTENT`: semantic confidence is too low and multiple interpretations are plausible. +- `NO_DATA`: plan is valid but no rows exist in scope. +- `AI_UNAVAILABLE`: AI Planning or AI report generation failed; templates and deterministic reports can still work when possible. +- `INVALID_PLAN`: AI proposed or user requested an invalid plan after validation. + +Fallback order: + +1. Template or deterministic strategy with deterministic report. +2. AI report over Metric Result when provider is available. +3. Deterministic report summary if AI is unavailable. +4. Structured error/no-data response. + +## Testing Strategy + +### Unit Tests + +- Semantic Layer maps known phrases to expected concepts and confidence levels. +- Metric Catalog rejects unknown metrics, unsupported dimensions, unsupported analysis types, and deprecated metrics. +- Analysis Strategy chooses Template before Rule Composition before AI Planning. +- Rule Composition produces deterministic plans for examples such as delay reason trend. +- Analysis Plan Processor validates and normalizes time ranges, scope, Top N, dimensions, and metric versions. +- No Data Strategy returns structured no-data responses. +- ChartSpec Builder emits renderer-agnostic ChartSpec, not raw ECharts options. +- Evidence items include source domain and drilldown filters when available. + +### Service Tests + +- Normal member cannot query all-company management scope. +- Project Owner/Admin can query managed project scope. +- Version detail context restricts analysis to current version. +- Current-state risk queries do not use last 30 days by default. +- Trend/effort/throughput queries use last 30 days when no range is specified. +- Comparison queries use last 30 days versus previous 30 days when no baseline is specified. + +### Frontend Tests + +- AI Assistant renders Insight Card, chart, report, evidence, and follow-ups. +- Product/project/version context passes correct IDs to the analysis endpoint. +- ChartRenderer converts Unified ChartSpec to ECharts options through a single renderer boundary. +- Long labels and Top N bars do not overflow on desktop or mobile. +- No-data and no-permission states render as clear non-chart answers. + +### Visual QA + +- Verify Apple Vision rules on light and dark backgrounds. +- Verify line charts have smooth curves, area gradient, minimal axes, and anomaly markers. +- Verify horizontal bars are single-color, rounded, and animated softly. +- Verify number cards make the number the primary visual element. + +## Documentation Updates + +This design affects: + +- `docs/architecture.md`: add Business Analysis Agent layer. +- `docs/decisions.md`: add decision for Semantic Layer, Analysis Strategy, Metric Catalog, and unified ChartSpec. +- `docs/workflow.md`: add business analysis workflow. +- `docs/roadmap.md`: add V3 Business Analysis Agent stage. +- `docs/agent-spec.md`: add Business Analysis Agent contract summary.