# 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<string, string | number | boolean | string[] | number[]>;
  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<Record<string, string | number | null>>;
  totals?: Record<string, string | number>;
  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<string, unknown>;
  };
};
```

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<Record<string, string | number | null>>;
    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<string, unknown>;
    }
  | {
      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.
