/**
 * SF-02 Requirement Engineering Factory — Test Suite
 *
 * Part S：全覆盖测试
 *
 * 覆盖：
 *   A — Requirement Domain Model
 *   B — Strategy Conversion Engine
 *   C — Epic Generation Test
 *   D — Feature Generation Test
 *   E — User Story Generation Test
 *   F — Acceptance Criteria Generation Test
 *   G — Business Rules Generation Test
 *   H — Permission Requirement Test
 *   I — NFR Generation Test
 *   J — Integration Requirement Test
 *   K — Data Requirement Test
 *   L — Dependency Graph Test
 *   M — Priority Matrix Test
 *   N — MVP Scope Test
 *   O — Traceability Test
 *   P — Requirement Package Test
 *   Q — Factory Integration Test (PR-36)
 *   R — Artifact Registration Test
 *   S — Runtime Integration Test (PR-35)
 *   T — SF-01 Compatibility Test
 *   U — Edge Cases Test
 */

import { describe, it } from "node:test";
import assert from "node:assert/strict";

// ─── SF-02 Domain Model ──────────────────────────
import * as dm from "../src/sf-02-requirement-engineering/domain-model.mjs";

// ─── SF-02 Conversion Engine ─────────────────────
import {
  convertStrategyToRequirements,
  generateEpicsFromStrategy,
  generateFeaturesFromEpic,
  generateUserStoriesFromFeature,
  generateAcceptanceCriteriaForStory,
  generateIntegrationRequirements,
  generateNFRs,
  generatePermissionRequirements,
  generateBusinessRules,
  generateDataRequirements,
  generateConstraints,
} from "../src/sf-02-requirement-engineering/strategy-to-requirement.mjs";

// ─── SF-02 Dependency & Priority & MVP & Trace ────
import {
  buildDependencyGraph,
  buildPriorityMatrix,
  generateMVPScope,
  buildTraceabilityMatrix,
  prioritizeByMoSCoW,
  prioritizeByRICE,
  prioritizeByWSJF,
} from "../src/sf-02-requirement-engineering/dependency-engine.mjs";

// ─── SF-02 Factory ───────────────────────────────
import {
  sf02RequirementEngineeringFactory,
  registerSF02,
  generateRequirementReport,
  SF02_ARTIFACTS,
} from "../src/sf-02-requirement-engineering/index.mjs";

// ─── SF-01 (for compatibility test) ──────────────
import {
  sf01ProductStrategyFactory, registerSF01,
} from "../src/sf-01-product-strategy/index.mjs";

// ─── PR-36 Factory Core ──────────────────────────
import { createFactoryRegistry } from "../src/software-factory-core/factory-registry.mjs";
import { createFactoryInput, createFactoryOutput } from "../src/software-factory-core/factory-contract.mjs";
import { createArtifactGraph, createArtifactNode } from "../src/software-factory-core/artifact-graph.mjs";

// ─── PR-35 Runtime ───────────────────────────────
import {
  createTask, createExecutionPlan, createRuntimeContext, executePipeline,
} from "../src/agent-runtime/index.mjs";

// ═════════════════════════════════════════════════════
// Test Fixture: Mock Strategy Package
// ═════════════════════════════════════════════════════

function mockStrategyPackage(category = "AI平台") {
  return {
    executiveSummary: {
      title: "Product Strategy: AI客服平台",
      viabilityVerdict: "STRONG_GO",
      viabilityScore: 82,
      priorityLevel: "P0",
      recommendation: "强烈建议立即启动",
    },
    problemStatement: {
      who: "中小企业客服团队",
      what: "客服效率低，知识管理混乱",
      why: "人工客服成本高，响应慢",
      severity: 75,
    },
    targetCustomer: {
      segment: "中小企业",
      willingnessToPay: 70,
      painPoints: ["客服效率低", "知识碎片化", "培训成本高"],
    },
    targetMarket: {
      tam: 50_000_000_000,
      sam: 5_000_000_000,
      som: 500_000_000,
      growthRate: 35,
    },
    businessModel: { type: "SaaS", ltvCacRatio: 5.2, grossMargin: 85 },
    revenueModel: { year1Revenue: 2_000_000 },
    productVision: {
      vision: "让每个企业拥有智能客服",
      mission: "通过AI技术降低客服成本80%",
    },
    riskAssessment: { overallRisk: 40, breakdown: { marketRisk: 30, techRisk: 50 } },
    gtmStrategy: { entryStrategy: "PLG", timeToMarketMonths: 6, initialBudget: 500_000 },
    roadmap: {
      totalDurationMonths: 18,
      totalBudget: 2_000_000,
      phases: [
        { phase: "mvp", scope: "核心AI客服功能", durationMonths: 6, budget: 500_000 },
        { phase: "v1", scope: "多语言+多渠道", durationMonths: 6, budget: 700_000 },
        { phase: "v2", scope: "高级分析+自动化", durationMonths: 4, budget: 500_000 },
        { phase: "enterprise", scope: "企业版功能", durationMonths: 2, budget: 300_000 },
      ],
    },
    metadata: { factoryId: "SF-01", category, version: "1.0" },
  };
}

// ═════════════════════════════════════════════════════
// A — Requirement Domain Model
// ═════════════════════════════════════════════════════

describe("SF-02 Part A — Requirement Domain Model", () => {

  it("creates a valid Epic", () => {
    const epic = dm.createEpic({
      title: "知识库管理",
      description: "知识文档的全生命周期管理",
      category: dm.EPIC_CATEGORY.CONTENT_MANAGEMENT,
      objective: "构建高质量知识体系",
    });
    assert.ok(epic.id.startsWith("ep-"));
    assert.equal(epic.title, "知识库管理");
    assert.equal(epic.category, "内容管理");
    assert.equal(epic.objective, "构建高质量知识体系");
  });

  it("creates a valid Feature", () => {
    const feature = dm.createFeature({
      title: "知识库创建",
      description: "创建知识库并设置基本属性",
      epicId: "ep-1",
      featureType: "CRUD",
    });
    assert.ok(feature.id.startsWith("ft-"));
    assert.equal(feature.epicId, "ep-1");
    assert.equal(feature.featureType, "CRUD");
  });

  it("creates a valid UserStory with standard format", () => {
    const story = dm.createUserStory({
      role: "客服人员",
      goal: "快速搜索知识库",
      value: "高效回答用户问题",
      featureId: "ft-1",
      epicId: "ep-1",
      priority: dm.STORY_PRIORITY.MUST_HAVE,
    });
    assert.ok(story.id.startsWith("us-"));
    assert.equal(story.role, "客服人员");
    assert.equal(story.goal, "快速搜索知识库");
    assert.equal(story.priority, "Must Have");
    assert.ok(story.statement.includes("As a 客服人员"));
    assert.ok(story.statement.includes("I want 快速搜索知识库"));
  });

  it("creates valid AcceptanceCriteria in Given/When/Then format", () => {
    const ac = dm.createAcceptanceCriteria({
      storyId: "us-1",
      scenario: "正常搜索",
      given: "用户已登录系统",
      when: "用户输入搜索关键词",
      then: "系统返回相关结果",
    });
    assert.ok(ac.id.startsWith("ac-"));
    assert.ok(ac.statement.includes("Given 用户已登录系统"));
    assert.ok(ac.statement.includes("When 用户输入搜索关键词"));
    assert.ok(ac.statement.includes("Then 系统返回相关结果"));
  });

  it("creates valid BusinessRule", () => {
    const br = dm.createBusinessRule({
      name: "密码安全策略",
      description: "密码必须满足安全要求",
      ruleType: dm.RULE_TYPE.CONSTRAINT,
      condition: "用户设置新密码",
      action: "验证密码复杂度",
    });
    assert.ok(br.id.startsWith("br-"));
    assert.equal(br.ruleType, "业务约束");
  });

  it("creates valid Constraint", () => {
    const ct = dm.createConstraint({
      name: "交付时间",
      description: "MVP 6 个月交付",
      constraintType: dm.CONSTRAINT_TYPE.TIME,
    });
    assert.ok(ct.id.startsWith("ct-"));
    assert.equal(ct.constraintType, "时间约束");
  });

  it("creates valid NFR", () => {
    const nfr = dm.createNonFunctionalRequirement({
      name: "页面响应时间",
      description: "页面需快速响应",
      category: dm.NFR_CATEGORY.PERFORMANCE,
      metric: "P95 响应时间",
      target: "< 500ms",
    });
    assert.ok(nfr.id.startsWith("nfr-"));
    assert.equal(nfr.category, "性能需求");
  });

  it("creates valid PermissionRequirement", () => {
    const pr = dm.createPermissionRequirement({
      accessModel: dm.ACCESS_MODEL.HYBRID,
      roles: [
        { name: dm.ROLE_TYPE.SUPER_ADMIN, description: "超级管理员" },
        { name: dm.ROLE_TYPE.USER, description: "普通用户" },
      ],
      permissions: [
        { resource: "content", action: "read" },
        { resource: "content", action: "create" },
      ],
    });
    assert.equal(pr.accessModel, "Hybrid");
    assert.equal(pr.roles.length, 2);
    assert.equal(pr.permissions.length, 2);
  });

  it("creates valid IntegrationRequirement", () => {
    const ir = dm.createIntegrationRequirement({
      name: "支付集成",
      category: dm.INTEGRATION_CATEGORY.PAYMENT,
      description: "集成微信支付和支付宝",
      necessity: "required",
    });
    assert.ok(ir.id.startsWith("ir-"));
    assert.equal(ir.category, "支付系统");
  });

  it("creates valid DataRequirement (no DB design)", () => {
    const dr = dm.createDataRequirement({
      entityName: "用户 (User)",
      description: "平台用户基本信息",
      requiredFields: ["用户名", "邮箱", "密码哈希"],
      relationships: ["用户 → 角色（多对多）"],
      dataClassification: dm.DATA_CLASSIFICATION.PII,
      lifecycle: [dm.DATA_LIFECYCLE.CREATE, dm.DATA_LIFECYCLE.READ],
      owner: "用户本人 + 管理员",
      complianceReqs: ["GDPR", "个人信息保护法"],
    });
    assert.ok(dr.id.startsWith("dr-"));
    assert.equal(dr.dataClassification, "个人隐私数据");
    assert.equal(dr.owner, "用户本人 + 管理员");
  });

  it("creates valid RiskRequirement with score calculation", () => {
    const rr = dm.createRiskRequirement({
      name: "第三方API不稳定",
      description: "AI模型API可能不稳定",
      level: dm.RISK_LEVEL.HIGH,
      probability: 0.3,
      impact: 0.8,
    });
    assert.equal(rr.riskScore, 0.24);
    assert.equal(rr.level, "high");
  });

  it("creates valid TraceabilityLink", () => {
    const tl = dm.createTraceabilityLink({
      sourceId: "ep-1",
      sourceType: "epic",
      targetId: "ft-1",
      targetType: "feature",
      linkType: dm.LINK_TYPE.EPIC_TO_FEATURE,
    });
    assert.ok(tl.id.startsWith("tl-"));
    assert.equal(tl.linkType, "epic→feature");
  });

  it("creates valid Priority with RICE scoring", () => {
    const pri = dm.createPriority({
      itemId: "ep-1",
      itemType: "epic",
      category: dm.PRIORITY_CATEGORY.MUST_HAVE,
      method: dm.PRIORITY_METHOD.RICE,
      score: 65,
      scores: { reach: 80, impact: 3, confidence: 0.8, effort: 3 },
    });
    assert.equal(pri.category, "Must Have");
    assert.equal(pri.method, "RICE");
    // RICE: 80*3*0.8/3 = 64
    assert.ok(Math.abs(pri.score - 64) <= 2, `Expected ~64, got ${pri.score}`);
  });

  it("creates valid Dependency", () => {
    const dep = dm.createDependency({
      fromId: "ep-2",
      fromType: "epic",
      toId: "ep-1",
      toType: "epic",
      depType: dm.DEPENDENCY_TYPE.REQUIRED_BY,
      description: "Agent 管理需要用户管理",
    });
    assert.ok(dep.id.startsWith("dep-"));
    assert.equal(dep.depType, "required_by");
  });

  it("creates valid RequirementVersion", () => {
    const rv = dm.createRequirementVersion({
      requirementId: "us-5",
      requirementType: "story",
      versionNumber: 2,
      changeDescription: "更新了权限验证流程",
    });
    assert.equal(rv.versionNumber, 2);
  });

  it("creates complete RequirementPackage", () => {
    const pkg = dm.createRequirementPackage({
      productName: "AI客服平台",
      strategyPackage: mockStrategyPackage(),
      executiveSummary: { summary: "test" },
      epics: [dm.createEpic({ title: "t", description: "d", category: dm.EPIC_CATEGORY.SYSTEM })],
    });
    assert.equal(pkg.productName, "AI客服平台");
    assert.equal(pkg.epics.length, 1);
    assert.equal(pkg.metadata.factoryId, "SF-02");
  });

  it("Throws on required fields missing", () => {
    assert.throws(() => dm.createEpic({}), /title/);
    assert.throws(() => dm.createUserStory({}), /role/);
    assert.throws(() => dm.createAcceptanceCriteria({}), /storyId/);
    assert.throws(() => dm.createBusinessRule({}), /name/);
    assert.throws(() => dm.createConstraint({}), /name/);
    assert.throws(() => dm.createNonFunctionalRequirement({}), /name/);
    assert.throws(() => dm.createIntegrationRequirement({}), /name/);
    assert.throws(() => dm.createDataRequirement({}), /entityName/);
    assert.throws(() => dm.createDependency({}), /fromId/);
    assert.throws(() => dm.createPriority({}), /itemId/);
    assert.throws(() => dm.createTraceabilityLink({}), /sourceId/);
  });
});

// ═════════════════════════════════════════════════════
// B — Strategy Conversion Engine
// ═════════════════════════════════════════════════════

describe("SF-02 Part B — Strategy → Requirement Conversion", () => {

  it("converts AI platform strategy to requirements", () => {
    const strategy = mockStrategyPackage("AI平台");
    const result = convertStrategyToRequirements(strategy);

    assert.ok(result.epics.length >= 5, `Expected >=5 epics, got ${result.epics.length}`);
    assert.ok(result.features.length >= 15, `Expected >=15 features, got ${result.features.length}`);
    assert.ok(result.userStories.length >= 40, `Expected >=40 stories, got ${result.userStories.length}`);
    assert.ok(result.acceptanceCriteria.length >= 50, `Expected >=50 AC, got ${result.acceptanceCriteria.length}`);
    assert.ok(result.businessRules.length >= 5);
    assert.ok(result.nonFunctionalReqs.length >= 5);
    assert.ok(result.integrationReqs.length >= 3, `Expected >=3 integration reqs, got ${result.integrationReqs.length}`);
    assert.ok(result.dataReqs.length >= 3);
  });

  it("converts enterprise SaaS strategy", () => {
    const strategy = mockStrategyPackage("企业SaaS");
    const result = convertStrategyToRequirements(strategy);
    assert.ok(result.epics.length >= 5);
    assert.ok(result.features.length >= 15);
  });

  it("converts ecommerce strategy", () => {
    const strategy = mockStrategyPackage("电商平台");
    const result = convertStrategyToRequirements(strategy);
    const epicTitles = result.epics.map(e => e.title);
    assert.ok(epicTitles.some(t => t.includes("商品")), "Should have product management epic");
    assert.ok(epicTitles.some(t => t.includes("订单")), "Should have order management epic");
  });

  it("converts education platform strategy", () => {
    const strategy = mockStrategyPackage("教育平台");
    const result = convertStrategyToRequirements(strategy);
    const epicTitles = result.epics.map(e => e.title);
    assert.ok(epicTitles.some(t => t.includes("课程")));
    assert.ok(epicTitles.some(t => t.includes("学习")));
  });

  it("falls back to generic template for unknown category", () => {
    const strategy = mockStrategyPackage("量子计算平台");
    const result = convertStrategyToRequirements(strategy);
    assert.ok(result.epics.length >= 5, `Expected >=5 epics for unknown category, got ${result.epics.length}`);
  });

  it("empty strategy returns empty requirements", () => {
    const result = convertStrategyToRequirements({ metadata: { category: "通用" } });
    assert.equal(result.epics.length, 6); // generic template has 6
  });
});

// ═════════════════════════════════════════════════════
// C — Epic Generation
// ═════════════════════════════════════════════════════

describe("SF-02 Part C — Epic Generation", () => {

  it("generates AI platform epics with expected categories", () => {
    const strategy = mockStrategyPackage("AI平台");
    const epics = generateEpicsFromStrategy(strategy);

    const titles = epics.map(e => e.title);
    assert.ok(titles.includes("用户管理"), `Expected '用户管理', got: ${titles}`);
    assert.ok(titles.includes("知识库管理"), `Expected '知识库管理', got: ${titles}`);
    assert.ok(titles.includes("Agent管理"), `Expected 'Agent管理', got: ${titles}`);
    assert.ok(titles.includes("对话管理"), `Expected '对话管理', got: ${titles}`);
    assert.ok(titles.includes("权限管理"), `Expected '权限管理', got: ${titles}`);
    assert.ok(titles.includes("运营分析"), `Expected '运营分析', got: ${titles}`);
    assert.ok(titles.includes("系统设置"), `Expected '系统设置', got: ${titles}`);
  });

  it("each epic has required fields", () => {
    const epics = generateEpicsFromStrategy(mockStrategyPackage());
    for (const epic of epics) {
      assert.ok(epic.id, "Epic must have id");
      assert.ok(epic.title, "Epic must have title");
      assert.ok(epic.description, "Epic must have description");
      assert.ok(epic.category, "Epic must have category");
      assert.ok(epic.objective, "Epic must have objective");
      assert.ok(epic.successMetric, "Epic must have successMetric");
    }
  });
});

// ═════════════════════════════════════════════════════
// D — Feature Generation
// ═════════════════════════════════════════════════════

describe("SF-02 Part D — Feature Generation", () => {

  it("generates features from knowledge base epic", () => {
    const epic = dm.createEpic({
      title: "知识库管理", description: "知识管理", category: dm.EPIC_CATEGORY.CONTENT_MANAGEMENT,
      objective: "构建知识体系",
    });
    const features = generateFeaturesFromEpic(epic);

    assert.ok(features.length >= 3, `Expected >=3 features, got ${features.length}`);
    const titles = features.map(f => f.title);
    assert.ok(titles.includes("知识库创建"));
    assert.ok(titles.includes("文档上传"));
    assert.ok(titles.includes("索引构建"));
  });

  it("generates features from user management epic", () => {
    const epic = dm.createEpic({
      title: "用户管理", description: "用户管理", category: dm.EPIC_CATEGORY.USER_MANAGEMENT,
      objective: "用户身份管理",
    });
    const features = generateFeaturesFromEpic(epic);

    const titles = features.map(f => f.title);
    assert.ok(titles.includes("用户注册"));
    assert.ok(titles.includes("用户登录"));
    assert.ok(titles.includes("个人信息管理"));
  });

  it("all features reference correct epicId", () => {
    const epic = dm.createEpic({
      title: "知识库管理", description: "d", category: dm.EPIC_CATEGORY.CONTENT_MANAGEMENT,
      objective: "o",
    });
    const features = generateFeaturesFromEpic(epic);
    for (const f of features) {
      assert.equal(f.epicId, epic.id);
    }
  });

  it("generates fallback features for unknown epic titles", () => {
    const epic = dm.createEpic({
      title: "宇宙探索", description: "d", category: dm.EPIC_CATEGORY.SYSTEM,
      objective: "o",
    });
    const features = generateFeaturesFromEpic(epic);
    assert.ok(features.length >= 3);
    assert.ok(features[0].title.includes("宇宙探索"));
  });
});

// ═════════════════════════════════════════════════════
// E — User Story Generation
// ═════════════════════════════════════════════════════

describe("SF-02 Part E — User Story Generation", () => {

  it("generates CRUD stories", () => {
    const feature = dm.createFeature({
      title: "文档管理", description: "d", epicId: "ep-1", featureType: "CRUD",
    });
    const stories = generateUserStoriesFromFeature(feature, { title: "知识库" }, ["客服人员", "管理员"]);

    assert.ok(stories.length >= 4);
    const goals = stories.map(s => s.goal);
    assert.ok(goals.some(g => g.includes("浏览")), `Should have browse story, got: ${goals}`);
    assert.ok(goals.some(g => g.includes("创建")), `Should have create story, got: ${goals}`);
    assert.ok(goals.some(g => g.includes("编辑")), `Should have edit story, got: ${goals}`);
  });

  it("generates workflow stories", () => {
    const feature = dm.createFeature({
      title: "审批流程", description: "d", epicId: "ep-1", featureType: "workflow",
    });
    const stories = generateUserStoriesFromFeature(feature, { title: "业务流程" });
    assert.ok(stories.length >= 3);
    const goals = stories.map(s => s.goal);
    assert.ok(goals.some(g => g.includes("发起")), `Should have initiate story, got: ${goals}`);
  });

  it("generates analytics stories", () => {
    const feature = dm.createFeature({
      title: "数据看板", description: "d", epicId: "ep-1", featureType: "analytics",
    });
    const stories = generateUserStoriesFromFeature(feature, { title: "运营分析" });
    assert.ok(stories.length >= 3);
    const goals = stories.map(s => s.goal);
    assert.ok(goals.some(g => g.includes("导出")), `Should have export story, got: ${goals}`);
  });

  it("all stories use As a/I want/So that format", () => {
    const feature = dm.createFeature({
      title: "知识编辑", description: "d", epicId: "ep-1", featureType: "CRUD",
    });
    const stories = generateUserStoriesFromFeature(feature, { title: "知识库" }, ["用户"]);
    for (const story of stories) {
      assert.ok(story.statement.includes("As a "));
      assert.ok(story.statement.includes("I want "));
      assert.ok(story.statement.includes("so that "));
    }
  });

  it("assigns correct priority distribution", () => {
    const feature = dm.createFeature({
      title: "文档管理", description: "d", epicId: "ep-1", featureType: "CRUD",
    });
    const stories = generateUserStoriesFromFeature(feature, { title: "知识库" }, ["用户", "管理员"]);
    const mustHave = stories.filter(s => s.priority === "Must Have");
    const shouldHave = stories.filter(s => s.priority === "Should Have");
    const couldHave = stories.filter(s => s.priority === "Could Have");

    assert.ok(mustHave.length >= 1, "Must have at least 1 Must Have");
    assert.ok(shouldHave.length >= 1, "Must have at least 1 Should Have");
    assert.ok(couldHave.length >= 1, "Must have at least 1 Could Have");
  });
});

// ═════════════════════════════════════════════════════
// F — Acceptance Criteria
// ═════════════════════════════════════════════════════

describe("SF-02 Part F — Acceptance Criteria", () => {

  it("generates 3-10 ACs per story", () => {
    const story = dm.createUserStory({
      role: "用户", goal: "创建文档", value: "管理知识",
      featureId: "ft-1", epicId: "ep-1",
    });
    const acs = generateAcceptanceCriteriaForStory(story);
    assert.ok(acs.length >= 3, `Expected >=3 AC, got ${acs.length}`);
    assert.ok(acs.length <= 12);
  });

  it("all ACs use Given/When/Then format", () => {
    const story = dm.createUserStory({
      role: "用户", goal: "搜索知识", value: "快速查找",
      featureId: "ft-1", epicId: "ep-1",
    });
    const acs = generateAcceptanceCriteriaForStory(story);
    for (const ac of acs) {
      assert.ok(ac.given, `AC missing given: ${ac.scenario}`);
      assert.ok(ac.when, `AC missing when: ${ac.scenario}`);
      assert.ok(ac.then, `AC missing then: ${ac.scenario}`);
    }
  });

  it("covers normal flow, error flow, edge cases", () => {
    const story = dm.createUserStory({
      role: "用户", goal: "上传文档", value: "添加知识",
      featureId: "ft-1", epicId: "ep-1",
    });
    const acs = generateAcceptanceCriteriaForStory(story);
    const scenarios = acs.map(a => a.scenario);
    assert.ok(scenarios.some(s => s.includes("正常")), "Should have normal flow");
    assert.ok(scenarios.some(s => s.includes("空数据") || s.includes("验证")), "Should have edge case");
    assert.ok(scenarios.some(s => s.includes("权限")), "Should have permission check");
  });

  it("delete stories have delete-specific ACs", () => {
    const story = dm.createUserStory({
      role: "管理员", goal: "删除知识库", value: "清理无效数据",
      featureId: "ft-1", epicId: "ep-1",
    });
    const acs = generateAcceptanceCriteriaForStory(story);
    const scenarios = acs.map(a => a.scenario);
    assert.ok(scenarios.some(s => s.includes("确认")), `Expected delete confirmation, got: ${scenarios}`);
    assert.ok(scenarios.some(s => s.includes("关联")), `Expected related data check, got: ${scenarios}`);
  });

  it("search stories have search-specific ACs", () => {
    const story = dm.createUserStory({
      role: "用户", goal: "搜索文档内容", value: "快速定位信息",
      featureId: "ft-1", epicId: "ep-1",
    });
    const acs = generateAcceptanceCriteriaForStory(story);
    const scenarios = acs.map(a => a.scenario);
    assert.ok(scenarios.some(s => s.includes("搜索结果") || s.includes("无搜索")), `Expected search scenarios, got: ${scenarios}`);
  });
});

// ═════════════════════════════════════════════════════
// G — Business Rules
// ═════════════════════════════════════════════════════

describe("SF-02 Part G — Business Rules", () => {

  it("generates standard business rules", () => {
    const rules = generateBusinessRules(mockStrategyPackage());
    assert.ok(rules.length >= 5, `Expected >=5 rules, got ${rules.length}`);
  });

  it("covers all rule types", () => {
    const rules = generateBusinessRules(mockStrategyPackage());
    const types = rules.map(r => r.ruleType);
    assert.ok(types.includes("验证规则"), `Expected validation rule, got: ${types}`);
    assert.ok(types.includes("业务约束"), `Expected constraint rule, got: ${types}`);
    assert.ok(types.includes("流程规则"), `Expected process rule, got: ${types}`);
    assert.ok(types.includes("审批规则"), `Expected approval rule, got: ${types}`);
    assert.ok(types.includes("状态机规则"), `Expected state machine rule, got: ${types}`);
  });

  it("each business rule has condition and action", () => {
    const rules = generateBusinessRules(mockStrategyPackage());
    for (const r of rules) {
      assert.ok(r.condition, `Rule ${r.name} missing condition`);
      assert.ok(r.action, `Rule ${r.name} missing action`);
    }
  });
});

// ═════════════════════════════════════════════════════
// H — Permission Requirements
// ═════════════════════════════════════════════════════

describe("SF-02 Part H — Permission Requirements", () => {

  it("generates permission model with all standard roles", () => {
    const pr = generatePermissionRequirements(mockStrategyPackage());
    assert.equal(pr.accessModel, "Hybrid");

    const roleNames = pr.roles.map(r => r.name);
    assert.ok(roleNames.includes("超级管理员"));
    assert.ok(roleNames.includes("管理员"));
    assert.ok(roleNames.includes("运营人员"));
    assert.ok(roleNames.includes("普通用户"));
    assert.ok(roleNames.includes("访客"));
    assert.ok(roleNames.includes("审计员"));
  });

  it("provides role-permission mappings", () => {
    const pr = generatePermissionRequirements(mockStrategyPackage());
    assert.ok(pr.rolePermissions.length >= 4);
    const superAdmin = pr.rolePermissions.find(rp => rp.role === "超级管理员");
    assert.deepEqual(superAdmin.permissions, ["*"]);
  });

  it("AI platform has agent/conversation resources", () => {
    const pr = generatePermissionRequirements(mockStrategyPackage("AI平台"));
    assert.ok(pr.resourceTypes.includes("agent"));
    assert.ok(pr.resourceTypes.includes("conversation"));
  });
});

// ═════════════════════════════════════════════════════
// I — Non-Functional Requirements
// ═════════════════════════════════════════════════════

describe("SF-02 Part I — NFR Generation", () => {

  it("generates NFRs covering all categories", () => {
    const nfrs = generateNFRs(mockStrategyPackage());
    assert.ok(nfrs.length >= 8);

    const categories = nfrs.map(n => n.category);
    assert.ok(categories.includes("性能需求"));
    assert.ok(categories.includes("安全需求"));
    assert.ok(categories.includes("可靠性需求"));
    assert.ok(categories.includes("扩展性需求"));
    assert.ok(categories.includes("可观测性需求"));
  });

  it("each NFR has quantifiable metric and target", () => {
    const nfrs = generateNFRs(mockStrategyPackage());
    for (const nfr of nfrs) {
      assert.ok(nfr.metric, `NFR ${nfr.name} missing metric`);
      assert.ok(nfr.target, `NFR ${nfr.name} missing target`);
    }
  });

  it("enterprise scope raises availability target", () => {
    const enterpriseStrategy = mockStrategyPackage();
    enterpriseStrategy.roadmap.phases.push({
      phase: "enterprise", scope: "Enterprise", durationMonths: 4, budget: 500000,
    });
    const nfrs = generateNFRs(enterpriseStrategy);
    const availability = nfrs.find(n => n.name === "系统可用性");
    assert.ok(availability.target.includes("99.99"));
  });
});

// ═════════════════════════════════════════════════════
// J — Integration Requirements
// ═════════════════════════════════════════════════════

describe("SF-02 Part J — Integration Requirements", () => {

  it("generates AI platform integration requirements", () => {
    const irs = generateIntegrationRequirements("AI平台");
    assert.ok(irs.length >= 4);
    const names = irs.map(ir => ir.name);
    assert.ok(names.some(n => n.includes("AI模型")));
    assert.ok(names.some(n => n.includes("邮件")));
    assert.ok(names.some(n => n.includes("搜索")));
  });

  it("generates ecommerce integration requirements", () => {
    const irs = generateIntegrationRequirements("电商平台");
    const names = irs.map(ir => ir.name);
    assert.ok(names.some(n => n.includes("支付")));
  });

  it("each integration requirement has providers listed", () => {
    const irs = generateIntegrationRequirements("AI平台");
    for (const ir of irs) {
      if (ir.necessity === "required") {
        assert.ok(ir.providers.length >= 1, `${ir.name} should have providers`);
      }
    }
  });
});

// ═════════════════════════════════════════════════════
// K — Data Requirements
// ═════════════════════════════════════════════════════

describe("SF-02 Part K — Data Requirements", () => {

  it("generates data requirements from epics (no DB design)", () => {
    const strategy = mockStrategyPackage("AI平台");
    const epics = generateEpicsFromStrategy(strategy);
    const dataReqs = generateDataRequirements(epics, strategy);

    assert.ok(dataReqs.length >= 4);

    // Verify it's NOT a database design (no column types, no normalization)
    for (const dr of dataReqs) {
      assert.ok(dr.entityName, "Must have entity name");
      assert.ok(dr.description, "Must have business description");
      assert.ok(dr.dataClassification, "Must have data classification");
      assert.ok(dr.owner, "Must have data owner");
      assert.ok(Array.isArray(dr.lifecycle));
      // Must NOT contain SQL or table definition patterns
      const allKeys = JSON.stringify(dr).toLowerCase();
      assert.ok(!allKeys.includes("varchar"), "Must not contain SQL types");
      assert.ok(!allKeys.includes("primary key"), "Must not contain DB design");
    }
  });

  it("includes user data requirement with PII classification", () => {
    const dataReqs = generateDataRequirements(
      generateEpicsFromStrategy(mockStrategyPackage()),
      mockStrategyPackage()
    );
    const userReq = dataReqs.find(d => d.entityName.includes("用户"));
    assert.ok(userReq);
    assert.equal(userReq.dataClassification, "个人隐私数据");
    assert.ok(userReq.complianceReqs.some(c => c.includes("GDPR")));
  });

  it("includes audit log requirement", () => {
    const dataReqs = generateDataRequirements(
      generateEpicsFromStrategy(mockStrategyPackage()),
      mockStrategyPackage()
    );
    const logReq = dataReqs.find(d => d.entityName.includes("日志"));
    assert.ok(logReq, "Must include audit log data requirement");
  });
});

// ═════════════════════════════════════════════════════
// L — Dependency Graph
// ═════════════════════════════════════════════════════

describe("SF-02 Part L — Dependency Graph", () => {

  it("builds dependency graph from requirements", () => {
    const strategy = mockStrategyPackage("AI平台");
    const req = convertStrategyToRequirements(strategy);
    const { dependencies, graph } = buildDependencyGraph(req);

    assert.ok(dependencies.length >= 5, `Expected >=5 dependencies, got ${dependencies.length}`);
    assert.ok(graph.nodes.length > 0);
    assert.ok(graph.edges.length > 0);
  });

  it("establishes epic-level dependencies", () => {
    const req = convertStrategyToRequirements(mockStrategyPackage("AI平台"));
    const { dependencies } = buildDependencyGraph(req);

    const epicDeps = dependencies.filter(d => d.fromType === "epic" && d.toType === "epic");
    assert.ok(epicDeps.length >= 2, `Expected >=2 epic deps, got ${epicDeps.length}`);
  });

  it("establishes story-level CRUD dependencies", () => {
    const req = convertStrategyToRequirements(mockStrategyPackage("AI平台"));
    const { dependencies } = buildDependencyGraph(req);

    const storyDeps = dependencies.filter(d => d.fromType === "story");
    assert.ok(storyDeps.length >= 3, `Expected >=3 story deps, got ${storyDeps.length}`);
  });
});

// ═════════════════════════════════════════════════════
// M — Priority Matrix
// ═════════════════════════════════════════════════════

describe("SF-02 Part M — Priority Matrix", () => {

  it("MoSCoW prioritization produces all 4 categories", () => {
    const items = Array.from({ length: 20 }, (_, i) => ({
      id: `item-${i}`, title: `Item ${i}`,
    }));
    const priorities = prioritizeByMoSCoW(items, "story", mockStrategyPackage());

    assert.equal(priorities.length, 20);
    const mustHave = priorities.filter(p => p.category === "Must Have");
    const shouldHave = priorities.filter(p => p.category === "Should Have");
    const couldHave = priorities.filter(p => p.category === "Could Have");
    const wontHave = priorities.filter(p => p.category === "Won't Have");

    assert.ok(mustHave.length > 0, "Must have Must Have items");
    assert.ok(shouldHave.length > 0, "Must have Should Have items");
    assert.ok(couldHave.length > 0, "Must have Could Have items");
    assert.ok(wontHave.length > 0, "Must have Won't Have items");
  });

  it("system setup epic is always Must Have", () => {
    const items = [
      { id: "ep-1", title: "系统设置" },
      { id: "ep-2", title: "用户管理" },
    ];
    const priorities = prioritizeByMoSCoW(items, "epic", mockStrategyPackage());
    const sysEpic = priorities.find(p => p.itemId === "ep-1");
    assert.equal(sysEpic.category, "Must Have", "System setup should be Must Have");
  });

  it("RICE prioritization calculates correct formula", () => {
    const items = Array.from({ length: 10 }, (_, i) => ({
      id: `item-${i}`, title: `Item ${i}`,
    }));
    const priorities = prioritizeByRICE(items, "feature", mockStrategyPackage());

    assert.equal(priorities.length, 10);
    for (const p of priorities) {
      assert.ok(p.scores.reach > 0);
      assert.ok(p.scores.impact > 0);
      assert.ok(p.scores.confidence > 0);
      assert.ok(p.scores.effort > 0);
    }
  });

  it("WSJF prioritization calculates CoD/Duration", () => {
    const items = Array.from({ length: 10 }, (_, i) => ({
      id: `item-${i}`, title: `Item ${i}`,
    }));
    const priorities = prioritizeByWSJF(items, "story");

    assert.equal(priorities.length, 10);
    for (const p of priorities) {
      assert.ok(p.scores.costOfDelay > 0);
      assert.ok(p.scores.jobDuration > 0);
    }
  });

  it("buildPriorityMatrix returns combined results", () => {
    const items = Array.from({ length: 10 }, (_, i) => ({
      id: `item-${i}`, title: `Item ${i}`,
    }));
    const { priorities, matrix } = buildPriorityMatrix(items, "feature", mockStrategyPackage());

    assert.equal(priorities.length, 10);
    assert.ok(matrix.mustHave.length > 0);
    assert.ok(matrix.shouldHave.length > 0);
    assert.ok(matrix.couldHave.length > 0);
    assert.ok(matrix.wontHave.length > 0);

    const total = Object.values(matrix.summary).reduce((a, b) => a + b, 0);
    assert.equal(total, 10);
  });
});

// ═════════════════════════════════════════════════════
// N — MVP Scope
// ═════════════════════════════════════════════════════

describe("SF-02 Part N — MVP Scope", () => {

  it("generates MVP scope aligned with roadmap", () => {
    const strategy = mockStrategyPackage("AI平台");
    const req = convertStrategyToRequirements(strategy);
    const epicPri = buildPriorityMatrix(req.epics, "epic", strategy);
    const featurePri = buildPriorityMatrix(req.features, "feature", strategy);
    const storyPri = buildPriorityMatrix(req.userStories, "story", strategy);

    const mvpScope = generateMVPScope({
      strategyPackage: strategy,
      epicPriorities: epicPri.priorities,
      featurePriorities: featurePri.priorities,
      storyPriorities: storyPri.priorities,
      epics: req.epics,
      features: req.features,
      userStories: req.userStories,
    });

    assert.ok(mvpScope.phases.length >= 4);
    assert.ok(mvpScope.mvp.userStories > 0, `MVP must have stories, got ${mvpScope.mvp.userStories}`);
    assert.ok(mvpScope.mvp.totalStoryPoints > 0);

    // V1 >= MVP
    assert.ok(mvpScope.v1.userStories >= mvpScope.mvp.userStories,
      `V1 stories (${mvpScope.v1.userStories}) must >= MVP stories (${mvpScope.mvp.userStories})`);

    // V2 >= V1
    assert.ok(mvpScope.v2.userStories >= mvpScope.v1.userStories);
  });

  it("MVP only contains Must Have items", () => {
    const strategy = mockStrategyPackage("AI平台");
    const req = convertStrategyToRequirements(strategy);
    const storyPri = buildPriorityMatrix(req.userStories, "story", strategy);

    const mvpScope = generateMVPScope({
      strategyPackage: strategy,
      epicPriorities: [],
      featurePriorities: [],
      storyPriorities: storyPri.priorities,
      epics: req.epics,
      features: req.features,
      userStories: req.userStories,
    });

    const mustHaveStories = storyPri.priorities.filter(p => p.category === "Must Have");
    assert.equal(mvpScope.mvp.userStories, mustHaveStories.length,
      `MVP should have ${mustHaveStories.length} stories, got ${mvpScope.mvp.userStories}`);
  });
});

// ═════════════════════════════════════════════════════
// O — Traceability Matrix
// ═════════════════════════════════════════════════════

describe("SF-02 Part O — Traceability", () => {

  it("builds complete traceability matrix from requirements", () => {
    const strategy = mockStrategyPackage("AI平台");
    const req = convertStrategyToRequirements(strategy);
    const { links, matrix } = buildTraceabilityMatrix(req);

    assert.ok(links.length >= 20, `Expected >=20 traceability links, got ${links.length}`);
    assert.ok(matrix.strategyToEpic > 0);
    assert.ok(matrix.epicToFeature > 0);
    assert.ok(matrix.featureToStory > 0);
    assert.ok(matrix.storyToAC > 0);
  });

  it("traces every epic back to strategy", () => {
    const req = convertStrategyToRequirements(mockStrategyPackage("AI平台"));
    const { links } = buildTraceabilityMatrix(req);

    const epicIds = req.epics.map(e => e.id);
    const tracedEpics = new Set(
      links.filter(l => l.linkType === "strategy→epic").map(l => l.targetId)
    );
    assert.equal(tracedEpics.size, epicIds.length,
      `All ${epicIds.length} epics should be traced, got ${tracedEpics.size}`);
  });

  it("traces every feature to an epic", () => {
    const req = convertStrategyToRequirements(mockStrategyPackage("AI平台"));
    const { links } = buildTraceabilityMatrix(req);

    const featureIds = req.features.map(f => f.id);
    const tracedFeatures = new Set(
      links.filter(l => l.linkType === "epic→feature").map(l => l.targetId)
    );
    assert.equal(tracedFeatures.size, featureIds.length,
      `All features should be traced to epics`);
  });

  it("traces every story to a feature", () => {
    const req = convertStrategyToRequirements(mockStrategyPackage("AI平台"));
    const { links } = buildTraceabilityMatrix(req);

    const storyIds = req.userStories.map(s => s.id);
    const tracedStories = new Set(
      links.filter(l => l.linkType === "feature→story").map(l => l.targetId)
    );
    assert.equal(tracedStories.size, storyIds.length,
      `All stories should be traced to features`);
  });

  it("every acceptance criteria is traced to its story", () => {
    const req = convertStrategyToRequirements(mockStrategyPackage("AI平台"));
    const { links } = buildTraceabilityMatrix(req);

    const acIds = req.acceptanceCriteria.map(a => a.id);
    const tracedACs = new Set(
      links.filter(l => l.linkType === "story→ac").map(l => l.targetId)
    );
    assert.equal(tracedACs.size, acIds.length,
      `All ${acIds.length} ACs should be traced, got ${tracedACs.size}`);
  });
});

// ═════════════════════════════════════════════════════
// P — Requirement Package
// ═════════════════════════════════════════════════════

describe("SF-02 Part P — Requirement Package", () => {

  it("generates complete requirement report markdown", () => {
    const strategy = mockStrategyPackage("AI平台");
    const req = convertStrategyToRequirements(strategy);
    const epics = req.epics;
    const report = generateRequirementReport({
      productName: "AI客服平台",
      strategyPackage: strategy,
      executiveSummary: { epicCount: epics.length },
      epics: req.epics,
      features: req.features,
      userStories: req.userStories,
      acceptanceCriteria: req.acceptanceCriteria,
      businessRules: req.businessRules,
      nonFunctionalReqs: req.nonFunctionalReqs,
      integrationReqs: req.integrationReqs,
      dataReqs: req.dataReqs,
      permissionReqs: [req.permissionReqs],
    });

    assert.ok(report.includes("Requirement Package: AI客服平台"));
    assert.ok(report.includes("Executive Summary"));
    assert.ok(report.includes("Epic Catalog"));
    assert.ok(report.includes("User Story Catalog"));
    assert.ok(report.includes("MVP Scope"));
    assert.ok(report.includes("Priority Distribution"));
    assert.ok(report.includes("Traceability Coverage"));
  });
});

// ═════════════════════════════════════════════════════
// Q — Factory Integration (PR-36)
// ═════════════════════════════════════════════════════

describe("SF-02 Part Q — Factory Integration (PR-36)", () => {

  it("registers in PR-36 Factory Registry", () => {
    const registry = createFactoryRegistry();
    registerSF02(registry);

    const sf02 = registry.get("SF-02");
    assert.equal(sf02.id, "SF-02");
    assert.equal(sf02.status, "active");
    assert.equal(sf02.domain, "requirement-engineering");
  });

  it("executes SF-02 factory with SF-01 output as input", () => {
    const registry = createFactoryRegistry();
    registerSF01(registry);
    registerSF02(registry);

    // Step 1: Run SF-01
    const sf01Input = createFactoryInput({
      factoryId: "SF-01",
      parameters: { idea: "开发一个AI Agent平台" },
    });
    const sf01Output = registry.execute("SF-01", sf01Input);
    assert.equal(sf01Output.status, "passed", `SF-01 should pass, got: ${sf01Output.status}`);

    // Step 2: Run SF-02 with SF-01 output
    const sf02Input = createFactoryInput({
      factoryId: "SF-02",
      upstreamArtifacts: sf01Output.artifacts,
    });
    const sf02Output = registry.execute("SF-02", sf02Input);

    assert.equal(sf02Output.status, "passed", `SF-02 should pass, got: ${sf02Output.status} — ${sf02Output.error || ''}`);
    assert.ok(sf02Output.artifacts.length >= 10, `Expected >=10 artifacts, got ${sf02Output.artifacts.length}`);
    assert.ok(sf02Output.metrics.length >= 8);
  });

  it("SF-02 fails with no upstream artifacts", () => {
    const registry = createFactoryRegistry();
    registerSF02(registry);

    const input = createFactoryInput({
      factoryId: "SF-02",
      upstreamArtifacts: [],
    });
    const output = registry.execute("SF-02", input);

    assert.equal(output.status, "failed");
    assert.ok(output.error.includes("SF-01"));
  });

  it("factory output contains all required artifact types", () => {
    const registry = createFactoryRegistry();
    registerSF01(registry);
    registerSF02(registry);

    const sf01Output = registry.execute("SF-01", createFactoryInput({
      factoryId: "SF-01", parameters: { idea: "AI Agent平台" },
    }));
    const sf02Output = registry.execute("SF-02", createFactoryInput({
      factoryId: "SF-02", upstreamArtifacts: sf01Output.artifacts,
    }));

    const artifactTypes = sf02Output.artifacts.map(a => a.metadata?.artifactType);
    assert.ok(artifactTypes.includes(SF02_ARTIFACTS.REQUIREMENT_PACKAGE));
    assert.ok(artifactTypes.includes(SF02_ARTIFACTS.EPIC_CATALOG));
    assert.ok(artifactTypes.includes(SF02_ARTIFACTS.FEATURE_CATALOG));
    assert.ok(artifactTypes.includes(SF02_ARTIFACTS.USER_STORY_CATALOG));
    assert.ok(artifactTypes.includes(SF02_ARTIFACTS.ACCEPTANCE_CRITERIA_PACKAGE));
    assert.ok(artifactTypes.includes(SF02_ARTIFACTS.BUSINESS_RULES_CATALOG));
    assert.ok(artifactTypes.includes(SF02_ARTIFACTS.PERMISSION_REQUIREMENTS));
    assert.ok(artifactTypes.includes(SF02_ARTIFACTS.NFR_PACKAGE));
    assert.ok(artifactTypes.includes(SF02_ARTIFACTS.INTEGRATION_REQUIREMENTS));
    assert.ok(artifactTypes.includes(SF02_ARTIFACTS.DATA_REQUIREMENTS));
    assert.ok(artifactTypes.includes(SF02_ARTIFACTS.DEPENDENCY_GRAPH));
    assert.ok(artifactTypes.includes(SF02_ARTIFACTS.PRIORITY_MATRIX));
    assert.ok(artifactTypes.includes(SF02_ARTIFACTS.MVP_SCOPE));
    assert.ok(artifactTypes.includes(SF02_ARTIFACTS.TRACEABILITY_MATRIX));
  });

  it("SF-02 has correct dependency on SF-01 in registry", () => {
    const registry = createFactoryRegistry();
    const deps = registry.getDependencies("SF-02");
    assert.equal(deps.length, 1);
    assert.equal(deps[0].from, "SF-01");
    assert.equal(deps[0].kind, "data");
  });
});

// ═════════════════════════════════════════════════════
// R — Artifact Graph Registration
// ═════════════════════════════════════════════════════

describe("SF-02 Part R — Artifact Graph", () => {

  it("registers SF-02 artifacts in artifact graph", () => {
    const graph = createArtifactGraph();
    const registry = createFactoryRegistry();
    registerSF01(registry);
    registerSF02(registry);

    const sf01Out = registry.execute("SF-01", createFactoryInput({
      factoryId: "SF-01", parameters: { idea: "AI Agent平台" },
    }));
    const sf02Out = registry.execute("SF-02", createFactoryInput({
      factoryId: "SF-02", upstreamArtifacts: sf01Out.artifacts,
    }));

    // Register SF-02 artifacts as ArtifactGraph nodes
    for (const art of sf02Out.artifacts) {
      const node = createArtifactNode({
        kind: art.kind,
        name: art.name,
        factoryId: art.factoryId,
        content: art.content,
        metadata: art.metadata,
      });
      graph.addNode(node);
    }

    const stats = graph.stats();
    assert.ok(stats.totalNodes >= 10, `Expected >=10 graph nodes, got ${stats.totalNodes}`);
  });
});

// ═════════════════════════════════════════════════════
// S — Runtime Integration (PR-35)
// ═════════════════════════════════════════════════════

describe("SF-02 Part S — Runtime Integration (PR-35)", () => {

  it("executes within PR-35 pipeline context", () => {
    const task = createTask({ id: "T-SF02-001", title: "SF-02 Requirement Engineering" });
    const plan = createExecutionPlan({ taskId: task.id, steps: [] });
    const ctx = createRuntimeContext({ task, plan });

    // Run SF-01 first
    const registry = createFactoryRegistry();
    registerSF01(registry);
    registerSF02(registry);

    const sf01Out = registry.execute("SF-01", createFactoryInput({
      factoryId: "SF-01", parameters: { idea: "智能客服系统" },
    }));

    // Then SF-02
    const sf02Out = registry.execute("SF-02", createFactoryInput({
      factoryId: "SF-02", upstreamArtifacts: sf01Out.artifacts,
    }));

    assert.equal(sf02Out.status, "passed");
    assert.ok(sf02Out.artifacts.length >= 10);
    assert.equal(sf02Out.metrics.length, 11, `Expected 11 metrics, got ${sf02Out.metrics.length}`);
  });
});

// ═════════════════════════════════════════════════════
// T — SF-01 Compatibility
// ═════════════════════════════════════════════════════

describe("SF-02 Part T — SF-01 Compatibility", () => {

  it("SF-02 correctly consumes SF-01 output artifacts", () => {
    const registry = createFactoryRegistry();
    registerSF01(registry);
    registerSF02(registry);

    // Test with multiple product ideas
    const ideas = ["AI Agent平台", "电商SaaS平台", "在线教育平台"];
    for (const idea of ideas) {
      const sf01Out = registry.execute("SF-01", createFactoryInput({
        factoryId: "SF-01", parameters: { idea },
      }));
      assert.equal(sf01Out.status, "passed", `SF-01 should pass for: ${idea}`);

      const sf02Out = registry.execute("SF-02", createFactoryInput({
        factoryId: "SF-02", upstreamArtifacts: sf01Out.artifacts,
      }));
      assert.equal(sf02Out.status, "passed", `SF-02 should pass for: ${idea} — ${sf02Out.error || ''}`);
      assert.ok(sf02Out.artifacts.length >= 10, `${idea}: expected >=10 artifacts, got ${sf02Out.artifacts.length}`);
    }
  });

  it("roadmap phase alignment: SF-01 → SF-02 MVP scope", () => {
    const registry = createFactoryRegistry();
    registerSF01(registry);
    registerSF02(registry);

    const sf01Out = registry.execute("SF-01", createFactoryInput({
      factoryId: "SF-01", parameters: { idea: "AI Agent平台" },
    }));

    // Extract roadmap from SF-01
    const roadmapArtifact = sf01Out.artifacts.find(a => a.metadata?.artifactType === "roadmap-report");
    assert.ok(roadmapArtifact, "SF-01 must produce roadmap");

    const sf02Out = registry.execute("SF-02", createFactoryInput({
      factoryId: "SF-02", upstreamArtifacts: sf01Out.artifacts,
    }));

    // Check MVP scope artifact
    const mvpArtifact = sf02Out.artifacts.find(a => a.metadata?.artifactType === SF02_ARTIFACTS.MVP_SCOPE);
    assert.ok(mvpArtifact, "SF-02 must produce MVP scope artifact");

    // Verify the scope metadata shows MVP stories
    assert.ok(mvpArtifact.metadata.mvpStories > 0, "MVP should have stories");
  });
});

// ═════════════════════════════════════════════════════
// U — Edge Cases
// ═════════════════════════════════════════════════════

describe("SF-02 Part U — Edge Cases", () => {

  it("handles empty strategy package gracefully", () => {
    const result = convertStrategyToRequirements({ metadata: { category: "通用" } });
    assert.ok(result.epics.length >= 5); // falls back to generic template
    assert.ok(result.features.length > 0);
    assert.ok(result.userStories.length > 0);
  });

  it("handles strategy with missing roadmap", () => {
    const strategy = { metadata: { category: "AI平台" } };
    const result = convertStrategyToRequirements(strategy);
    assert.ok(result.epics.length >= 5);
  });

  it("handles extremely large strategy (stress test)", () => {
    const strategy = mockStrategyPackage("AI平台");
    strategy.roadmap.phases.push(
      { phase: "v3", scope: "V3", durationMonths: 3, budget: 300000 },
      { phase: "v4", scope: "V4", durationMonths: 3, budget: 300000 },
      { phase: "v5", scope: "V5", durationMonths: 3, budget: 300000 },
    );
    const result = convertStrategyToRequirements(strategy);
    assert.ok(result.userStories.length >= 40);
    assert.ok(result.acceptanceCriteria.length >= 50);
  });

  it("no SQL or code artifacts in output", () => {
    const strategy = mockStrategyPackage("AI平台");
    const req = convertStrategyToRequirements(strategy);
    const allContent = JSON.stringify(req);
    assert.ok(!allContent.includes("CREATE TABLE"), "Must not contain SQL DDL");
    assert.ok(!allContent.includes("import React"), "Must not contain React code");
    assert.ok(!allContent.includes("function Component"), "Must not contain component code");
    assert.ok(!allContent.includes("PRIMARY KEY"), "Must not contain DB design");
    assert.ok(!allContent.includes("<div"), "Must not contain HTML/JSX");
  });

  it("generates valid IDs with correct prefixes", () => {
    const strategy = mockStrategyPackage("AI平台");
    const req = convertStrategyToRequirements(strategy);

    for (const e of req.epics) assert.ok(e.id.startsWith("ep-"));
    for (const f of req.features) assert.ok(f.id.startsWith("ft-"));
    for (const s of req.userStories) assert.ok(s.id.startsWith("us-"));
    for (const ac of req.acceptanceCriteria) assert.ok(ac.id.startsWith("ac-"));
    for (const br of req.businessRules) assert.ok(br.id.startsWith("br-"));
    for (const nfr of req.nonFunctionalReqs) assert.ok(nfr.id.startsWith("nfr-"));
    for (const ir of req.integrationReqs) assert.ok(ir.id.startsWith("ir-"));
    for (const dr of req.dataReqs) assert.ok(dr.id.startsWith("dr-"));
  });

  it("factory handles corrupted strategy artifact", () => {
    const registry = createFactoryRegistry();
    registerSF02(registry);

    const input = createFactoryInput({
      factoryId: "SF-02",
      upstreamArtifacts: [{
        id: "bad-artifact",
        kind: "requirement",
        name: "Corrupted Strategy",
        factoryId: "SF-01",
        metadata: { artifactType: "product-strategy-package" },
        content: "{invalid json!!!",
      }],
    });
    const output = registry.execute("SF-02", input);

    // Should fail gracefully, not crash
    assert.ok(output.status === "failed" || output.status === "passed",
      `Should complete without crash, got: ${output.status}`);
  });
});

// ═════════════════════════════════════════════════════
// V — Cross-Factory Compatibility
// ═════════════════════════════════════════════════════

describe("SF-02 Part V — PR-35 & PR-36 Compatibility", () => {

  it("PR-35 Runtime tests still pass", () => {
    // Verify no regression — PR-35 task creation works
    const task = createTask({ id: "T-COMPAT-001", title: "Compatibility Test" });
    assert.ok(task.id);
    assert.ok(task.title);
  });

  it("PR-36 Registry tests still pass", () => {
    const registry = createFactoryRegistry();
    // SF-01 and SF-02 both present; SF-03 removed (merged into SF-05)
    assert.ok(registry.get("SF-01"));
    assert.ok(registry.get("SF-02"));
    assert.equal(registry.get("SF-03"), null);

    const deps = registry.getDependencies("SF-02");
    assert.equal(deps.length, 1);
    assert.equal(deps[0].from, "SF-01");

    const dependents = registry.getDependents("SF-02");
    const depIds = dependents.map(d => d.id);
    // SF-03 removed; SF-05, SF-08 still depend on SF-02
    assert.ok(depIds.length >= 2, `Expected >=2 dependents on SF-02, got ${depIds.length}`);
    assert.ok(depIds.includes("SF-05"), "SF-05 should depend on SF-02");
    assert.ok(depIds.includes("SF-08"), "SF-08 should depend on SF-02");
  });

  it("topological order puts SF-01 before SF-02", () => {
    const registry = createFactoryRegistry();
    const order = registry.getTopologicalOrder();
    const sf01Idx = order.indexOf("SF-01");
    const sf02Idx = order.indexOf("SF-02");
    assert.ok(sf01Idx < sf02Idx, `SF-01 (${sf01Idx}) must come before SF-02 (${sf02Idx})`);
  });

  it("parallel batches: SF-02 is in batch 2 (after SF-01)", () => {
    const registry = createFactoryRegistry();
    const batches = registry.getParallelBatches();
    // Batch 1: SF-01
    assert.ok(batches[0].includes("SF-01"));
    // Batch 2: SF-02
    assert.ok(batches[1].includes("SF-02"));
  });
});
