/**
 * 批次一场景运行器 — 真实引擎函数调用
 *
 * 每个运行器调用实际引擎函数并返回按规则的通过/失败结果。
 * 场景 A/B/F 是异步的，执行深度引擎链路。
 */
import { routeIntent } from "../pipeline/intent_router.js";
import { expand } from "../pipeline/intent_expander.js";
import { resolveWorkflow } from "../workflow/workflow_contract_registry.js";
import { generateVerifyCommands } from "./verifier.js";
import { checkScope } from "../pipeline/scope_controller.js";
import { checkCorePrinciples } from "../audit/core_engineering_principles.js";
import { buildHookAdditionalContext, verifyHookAdditionalContextStructure, compareHookAndClassifyRouteDecision, } from "../pipeline/hook_context_types.js";
import { validateToolInvocation, findToolInvocationContractByName, classifyViolationSeverity, } from "../contracts/tool_invocation_contract_registry.js";
import { createCommandContract, canExecute, isForbiddenCommand, } from "../contracts/command_execution_contract.js";
import { scanTextSensitivity, evaluatePrivacyGate, redactSensitiveText, } from "../audit/privacy_secret_contract.js";
import { createUserFeedbackMessage, getAllowedFeedbackKinds, validateUserFeedbackContract, getStatusTemplate, } from "../contracts/user_feedback_contract.js";
import { orphanGate, createMainPathIntegrationContract, } from "../audit/main_path_integration_contract.js";
import crypto from "node:crypto";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { debug } from "../core/logger.js";
import { errorMessage } from "../core/helpers.js";
const testConfig = {
    name: "test-project",
    tech_stack: {
        backend: { lang: "java", framework: "spring-boot", version: "3" },
        frontend: { lang: "typescript", framework: "react", version: "18" },
    },
    product_profile: "saas",
    repos: [],
    build_commands: {
        backend: { build: "mvn compile", test: "mvn test", full: "mvn verify" },
        frontend: { build: "npm run build", test: "npm test", full: "npm run build && npm test" },
    },
    scope: { backend: ["src/"], frontend: ["src/"] },
};
// ── 场景 A: 源码提取 (异步，真实 expand 链路) ──
/**
 * 运行源码提取场景（场景 A）— 测试完整的 expand 链路。
 *
 * @returns 按规则的通过/失败结果列表
 */
export async function runScenarioSourceExtraction() {
    const rules = [];
    debug("场景运行", "开始执行场景 A — 源码提取");
    const intent = "从源码包 project-src.zip 提取并生成原型说明";
    // 1. 通过真实的 routeIntent 获取路由决策
    const routeDecision = routeIntent({ intent, task_id: "scenario-A" });
    // 2. 构造模拟知识索引，包含 source_extraction 所需条目
    const now = new Date().toISOString();
    const knowledgeEntries = [
        { id: "ke-原型说明模版", file_path: "templates/artifacts/shared/原型说明模版.md", name: "原型说明模版", type: "acceptance_template", when: "route=source_extraction,output_artifact.kind=prototype_spec", scope: ["source_extraction", "shared"], products: ["*"], created_at: now, updated_at: now, usage_count: 0, confidence: 1.0, status: "active" },
        { id: "ke-源码原型交付流程", file_path: "templates/procedures/源码原型交付流程.md", name: "源码原型交付流程", type: "pipeline_procedure", when: "route=source_extraction,source-prototype-to-delivery", scope: ["source_extraction", "shared"], products: ["*"], created_at: now, updated_at: now, usage_count: 0, confidence: 1.0, status: "active" },
    ];
    const mockKnowledgeIndex = {
        query: () => knowledgeEntries,
        markUsed: () => { },
    };
    // 确保归档文件有真实路径，供 expand() 处理
    for (const m of routeDecision.input_materials) {
        if (m.kind === "archive" && !m.path) {
            m.path = "project-src.zip";
        }
    }
    // 路径已提供 → 清空 missing_required_inputs，避免 expand() 返回澄清请求
    routeDecision.missing_required_inputs = [];
    // 3. 创建临时 src 固件并在 expand() 之前计算 beforeHash
    const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sf-snap-A-"));
    const srcDir = path.join(tmpDir, "src");
    fs.mkdirSync(srcDir, { recursive: true });
    fs.writeFileSync(path.join(srcDir, "App.ts"), "export const App = 1;", "utf-8");
    const computeHash = (dir) => {
        const files = fs.readdirSync(dir).sort();
        const hash = crypto.createHash("sha256");
        for (const f of files) {
            hash.update(f);
            hash.update(fs.readFileSync(path.join(dir, f)));
        }
        return hash.digest("hex").slice(0, 12);
    };
    const srcHashBeforeExpand = computeHash(srcDir);
    // 4. 调用真实的 expand()
    const classification = {
        task_type: "feature", risk: "low", complexity: "low", ambiguity: "low",
        affected_repos: [], mode: "autonomous", strategy: "full_pipeline",
    };
    const result = await expand({
        intent,
        classification,
        projectPath: tmpDir,
        config: testConfig,
        knowledgeIndex: mockKnowledgeIndex,
        route_decision: routeDecision,
        task_id: "scenario-A",
    });
    // 5. 对真实 ExpandResult 字段进行断言
    const wt = result.workflow_trace;
    rules.push({ rule: "route=source_extraction", status: wt?.route === "source_extraction" ? "PASS" : "FAIL", evidence: `workflow_trace.route=${wt?.route ?? "undefined"}` });
    rules.push({ rule: "execution_shape=single_artifact", status: wt?.execution_shape === "single_artifact" ? "PASS" : "FAIL", evidence: `execution_shape=${wt?.execution_shape ?? "undefined"}` });
    rules.push({ rule: "mutation_allowed=false", status: wt?.mutation_allowed === false ? "PASS" : "FAIL", evidence: `mutation_allowed=${wt?.mutation_allowed ?? "undefined"}` });
    const archiveMat = result.input_materials?.find(m => m.path_or_ref.includes(".zip"));
    rules.push({ rule: "input_materials 包含 archive", status: archiveMat ? "PASS" : "FAIL", evidence: `archive=${archiveMat?.path_or_ref ?? "not found"}, total=${result.input_materials?.length ?? 0}` });
    rules.push({ rule: "archive path/ref 非空", status: archiveMat && archiveMat.path_or_ref.length > 0 ? "PASS" : "FAIL", evidence: `archive path_or_ref="${archiveMat?.path_or_ref ?? ""}"` });
    const allRO = !result.input_materials?.some(m => m.access_mode === "read_write");
    rules.push({ rule: "input_materials read_only", status: allRO ? "PASS" : "FAIL", evidence: `all read-only: ${allRO}` });
    rules.push({ rule: "workflow_trace 存在", status: wt ? "PASS" : "FAIL", evidence: wt ? `workflow_id=${wt.workflow_id}` : "undefined" });
    rules.push({ rule: "workflow_trace.workflow_id=wf-source-extraction", status: wt?.workflow_id === "wf-source-extraction" ? "PASS" : "FAIL", evidence: `workflow_id=${wt?.workflow_id ?? "undefined"}` });
    const ir = result.injection_report;
    rules.push({ rule: "injection_report 存在", status: ir ? "PASS" : "FAIL", evidence: ir ? `injected_required=${ir.injected_required?.length ?? 0}, injected_supporting=${ir.injected_supporting?.length ?? 0}` : "undefined" });
    rules.push({ rule: "missing_required_knowledge=[]", status: ir && ir.missing_required_knowledge?.length === 0 ? "PASS" : "FAIL", evidence: `missing_required_knowledge count=${ir?.missing_required_knowledge?.length ?? "N/A"}` });
    const oa = result.output_artifact_record;
    rules.push({ rule: "output_artifact_record.kind=prototype_spec", status: oa?.kind === "prototype_spec" ? "PASS" : "FAIL", evidence: `output_artifact.kind=${oa?.kind ?? "undefined"}` });
    rules.push({ rule: "output_artifact_record.path 在 .soloforge/output/**", status: oa?.path?.includes(".soloforge/output") ? "PASS" : "FAIL", evidence: `output_artifact.path=${oa?.path ?? "undefined"}` });
    const ie = result.ingestion_evidences ?? [];
    const archiveEv = ie.find(e => e.detected_kind === "archive" || e.source_ref.includes(".zip"));
    rules.push({ rule: "ingestion_evidences 存在且包含 archive", status: ie.length > 0 && !!archiveEv ? "PASS" : "FAIL", evidence: `evidences=${ie.length}, archive=${!!archiveEv}` });
    const allSrcRef = ie.length > 0 && ie.every(e => e.source_ref.length > 0);
    rules.push({ rule: "ingestion_evidences[].source_ref 非空", status: allSrcRef ? "PASS" : "FAIL", evidence: `all source_ref non-empty: ${allSrcRef}` });
    const prompt = result.prompt ?? "";
    rules.push({ rule: "prompt 不含修改 src/ 指令", status: !prompt.includes("修改 src/") && !prompt.includes("edit src/") ? "PASS" : "FAIL", evidence: `prompt modify src/: ${prompt.includes("修改 src/")}` });
    rules.push({ rule: "prompt 不要求编译/测试", status: !prompt.includes("npm run build") && !prompt.includes("mvn compile") && !prompt.includes("npm test") ? "PASS" : "FAIL", evidence: `prompt build/test: ${prompt.includes("npm run build") || prompt.includes("mvn compile")}` });
    // artifact_ready: 创建带产物引用的 UserFeedbackMessage，验证契约
    const artifactReadyMsg = createUserFeedbackMessage({
        kind: "artifact_ready",
        title: "产物已生成：原型说明",
        summary: "源码包原型说明已生成",
        verified: ["artifact"],
        unverified: [],
        risks: [],
        references: oa ? [{ type: "artifact", ref: oa.path }] : [],
    });
    const artTemplate = getStatusTemplate("artifact_ready");
    const artContractFindings = validateUserFeedbackContract([artifactReadyMsg]);
    const artHardFail = artContractFindings.find(f => f.severity === "hard_fail");
    const artKindOk = artifactReadyMsg.kind === "artifact_ready";
    const artChineseOk = /[一-鿿]/.test(artTemplate);
    const artRefOk = artifactReadyMsg.references.some(r => r.ref === oa?.path);
    const artContractOk = !artHardFail;
    const artAllOk = artKindOk && artChineseOk && artRefOk && artContractOk;
    rules.push({ rule: "artifact_ready 中文反馈合法", status: artAllOk ? "PASS" : "FAIL", evidence: `kind=${artifactReadyMsg.kind}, Chinese=${artChineseOk}, ref=${artifactReadyMsg.references[0]?.ref ?? "none"}, contract=${artContractOk ? "pass" : artHardFail.rule}` });
    // 5. 计算 afterHash — expand() 不应修改 src/
    const srcHashAfterExpand = computeHash(srcDir);
    fs.rmSync(tmpDir, { recursive: true, force: true });
    const srcHashMatch = srcHashBeforeExpand === srcHashAfterExpand;
    rules.push({ rule: "src 快照 before/after 未变化", status: srcHashMatch ? "PASS" : "FAIL", evidence: `src_hash_before=${srcHashBeforeExpand}, src_hash_after=${srcHashAfterExpand}, match=${srcHashMatch}` });
    return rules;
}
// ── 场景 B: 代码变更 (异步，真实链路) ──
/**
 * 运行代码变更场景（场景 B）— 测试代码变更的完整链路。
 *
 * @returns 按规则的通过/失败结果列表
 */
export async function runScenarioCodeChange() {
    const rules = [];
    debug("场景运行", "开始执行场景 B — 代码变更");
    const changedFiles = ["src/main/java/LoginService.java"];
    const decision = routeIntent({ intent: "修复用户登录接口的空指针异常" });
    const routeOk = decision.route === "code_change" && decision.execution_shape === "code_execution" && decision.mutation_allowed === true;
    rules.push({ rule: "code_execution 必须走 workflow code_change 且 mutation_allowed=true", status: routeOk ? "PASS" : "FAIL", evidence: `route=${decision.route}, execution_shape=${decision.execution_shape}, mutation_allowed=${decision.mutation_allowed}` });
    const workflow = resolveWorkflow(decision);
    const wfOk = !!workflow && workflow.required_mechanisms.length > 0;
    rules.push({ rule: "WorkflowContract 存在且 required_mechanisms 非空", status: wfOk ? "PASS" : "FAIL", evidence: workflow ? `workflow.id=${workflow.id}, mechanisms=[${workflow.required_mechanisms.join(",")}]` : "undefined" });
    const acceptanceItems = [
        { id: "acc-build", description: "Build passes", type: "automated", check_command: "mvn compile" },
        { id: "acc-test", description: "Tests pass", type: "automated", check_command: "mvn test" },
    ];
    const verifyResult = generateVerifyCommands(testConfig, changedFiles, acceptanceItems, "code_change", "code_execution");
    const hasBuild = verifyResult.checks.build.length > 0;
    const hasTest = verifyResult.checks.tests.length > 0;
    rules.push({ rule: "VerificationPlan 存在，build/test commands 非空", status: hasBuild && hasTest ? "PASS" : "FAIL", evidence: `build=${verifyResult.checks.build.length}, test=${verifyResult.checks.tests.length}` });
    const verifyIsIndependent = typeof verifyResult === "object" && "checks" in verifyResult && "summary" in verifyResult && "manual_items" in verifyResult;
    rules.push({ rule: "VerificationResult 是独立对象，不得复用 VerificationPlan", status: verifyIsIndependent ? "PASS" : "FAIL", evidence: "VerifyResult has checks,summary,manual_items" });
    const incompleteReport = checkCorePrinciples({ route: "code_change", execution_shape: "code_execution", changed_files: changedFiles, declared_scope: ["src/main/java/"], has_goal_definition: true, has_verification_plan: true, verification_executed: false });
    rules.push({ rule: "verification_executed=false 时 overall_passed=false", status: !incompleteReport.overall_passed ? "PASS" : "FAIL", evidence: `verification_executed=false → overall_passed=${incompleteReport.overall_passed}` });
    const fullReport = checkCorePrinciples({ route: "code_change", execution_shape: "code_execution", changed_files: changedFiles, declared_scope: ["src/main/java/"], has_goal_definition: true, has_verification_plan: true, verification_executed: true, verification_passed: true });
    rules.push({ rule: "required knowledge 缺失必须报错 (完整链路通过)", status: fullReport.overall_passed ? "PASS" : "FAIL", evidence: `checkCorePrinciples → overall_passed=${fullReport.overall_passed}` });
    const noPlanReport = checkCorePrinciples({ route: "code_change", execution_shape: "code_execution", changed_files: changedFiles, declared_scope: ["src/main/java/"], has_goal_definition: true, has_verification_plan: false, verification_executed: false });
    const goalDriven = noPlanReport.principles.find(p => p.principle_id === "goal_driven_execution");
    rules.push({ rule: "verify 不允许 skip build+test", status: goalDriven?.status === "failed" ? "PASS" : "FAIL", evidence: `缺少 verification_plan → goal_driven_execution=${goalDriven?.status}` });
    const scopeWithin = await checkScope("src/main/java/LoginService.java", ["src/main/java/"]);
    rules.push({ rule: "ScopeLease declared_scope 内通过", status: scopeWithin.allowed ? "PASS" : "FAIL", evidence: `checkScope(within) → allowed=${scopeWithin.allowed}, severity=${scopeWithin.severity}` });
    const scopeOutside = await checkScope("src/other/Module.java", ["src/main/java/"]);
    rules.push({ rule: "declared_scope 外文件被检测", status: !scopeOutside.allowed ? "PASS" : "FAIL", evidence: `checkScope(outside) → allowed=${scopeOutside.allowed}, severity=${scopeOutside.severity}` });
    const orphanContract = createMainPathIntegrationContract({ module_path: "src/engine/orphan_module.ts", owner: "test", status: "implemented_not_integrated", production_imports: [], entry_traces: [], observability_refs: [], integration_tests: [] });
    const orphanFindings = orphanGate(orphanContract);
    rules.push({ rule: "orphanGate 能检测孤岛/无主链路接入", status: orphanFindings.length > 0 ? "PASS" : "FAIL", evidence: `orphanGate(isolated) → findings=${orphanFindings.length}` });
    rules.push({ rule: "workflow_trace 存在 (WorkflowContract)", status: workflow ? "PASS" : "FAIL", evidence: workflow ? `workflow.id=${workflow.id}` : "no workflow" });
    const noVerifyReport = checkCorePrinciples({ route: "code_change", execution_shape: "code_execution", changed_files: changedFiles, declared_scope: ["src/main/java/"], has_goal_definition: true, has_verification_plan: true, verification_executed: false });
    rules.push({ rule: "缺 VerificationResult 不得 completed", status: !noVerifyReport.overall_passed ? "PASS" : "FAIL", evidence: `no verification → overall_passed=${noVerifyReport.overall_passed}` });
    return rules;
}
// ── 场景 C: 隐私门禁 ──
/**
 * 运行隐私门场景（场景 C）— 测试敏感信息和 PII 拦截。
 *
 * @returns 按规则的通过/失败结果列表
 */
export function runScenarioPrivacyGate() {
    const rules = [];
    debug("场景运行", "开始执行场景 C — 隐私门");
    const secretResult = evaluatePrivacyGate({
        input_materials: [{ path_or_ref: "config/application.yml", content: "jwt_secret=sk-abcdefghijklmnopqrstuvwxyz1234567890abcdef" }],
    });
    rules.push({ rule: "secret 不得进入 prompt", status: secretResult.hard_fail ? "PASS" : "FAIL", evidence: `evaluatePrivacyGate → hard_fail=${secretResult.hard_fail}, blocked=[${secretResult.blocked_sources.join(",")}]` });
    const credResult = evaluatePrivacyGate({ input_materials: [{ path_or_ref: ".env" }] });
    rules.push({ rule: "credential 路径必须被拦截", status: credResult.hard_fail ? "PASS" : "FAIL", evidence: `evaluatePrivacyGate(.env) → hard_fail=${credResult.hard_fail}` });
    const piiText = "用户手机号13812345678，邮箱 test@example.com";
    const piiLabels = scanTextSensitivity(piiText, "test-pii-input");
    const hasPii = piiLabels.some(l => l.label === "pii");
    const { redacted } = redactSensitiveText(piiText, "test-pii-input");
    rules.push({ rule: "PII 必须被脱敏", status: hasPii && redacted !== piiText ? "PASS" : "FAIL", evidence: `labels=[${piiLabels.map(l => l.label).join(",")}], redacted=${redacted !== piiText}` });
    return rules;
}
// ── 场景 D: 命令验证 ──
/**
 * 运行命令验证场景（场景 D）— 测试命令执行约束。
 *
 * @returns 按规则的通过/失败结果列表
 */
export function runScenarioCommandValidation() {
    const rules = [];
    debug("场景运行", "开始执行场景 D — 命令验证");
    const planContract = createCommandContract({ command: "npm run build", cwd: "/project", source: "soloforge_generated", purpose: "build", mode: "plan_only" });
    const planExec = canExecute(planContract);
    rules.push({ rule: "destructive command 不得自动执行 (plan_only 不执行)", status: !planExec.allowed && planExec.reason.includes("plan_only") ? "PASS" : "FAIL", evidence: `canExecute(plan_only) → allowed=${planExec.allowed}` });
    const dbContract = createCommandContract({ command: "prisma migrate deploy", cwd: "/project", source: "soloforge_generated", purpose: "migrate", mode: "execute" });
    const dbExec = canExecute(dbContract);
    rules.push({ rule: "高风险命令需要人工确认", status: dbContract.requires_confirmation === "require_human" || !dbExec.allowed ? "PASS" : "FAIL", evidence: `risk=${dbContract.risk}, confirmation=${dbContract.requires_confirmation}` });
    const forbiddenResult = isForbiddenCommand("rm -rf /");
    rules.push({ rule: "forbidden command 必须被拦截", status: forbiddenResult.forbidden ? "PASS" : "FAIL", evidence: `isForbiddenCommand("rm -rf /") → forbidden=${forbiddenResult.forbidden}` });
    return rules;
}
// ── 场景 F: 阻断反馈 (异步，真实工具调用) ──
/**
 * 运行被阻反馈场景（场景 F）— 测试工具调用约束和反馈消息验证。
 *
 * @returns 按规则的通过/失败结果列表
 */
export async function runScenarioBlockedFeedback() {
    const rules = [];
    debug("场景运行", "开始执行场景 F — 被阻反馈");
    const allowedKinds = getAllowedFeedbackKinds("sf_verify");
    rules.push({ rule: "failedChecks > 0 时 kind 必须为 blocked", status: allowedKinds.includes("blocked") ? "PASS" : "FAIL", evidence: `getAllowedFeedbackKinds("sf_verify") → [${allowedKinds.join(",")}]` });
    const sfVerifyContract = findToolInvocationContractByName("sf_verify");
    const violations = validateToolInvocation({ tool_name: "sf_verify", current_next_allowed: ["sf_expand", "sf_classify"], current_forbidden: [], actual_side_effects: [], _contractOverride: sfVerifyContract });
    rules.push({ rule: "sf_verify 在 sf_expand 前调用 → ToolInvocationViolation", status: violations.length > 0 ? "PASS" : "FAIL", evidence: `validateToolInvocation(wrong order) → violations=${violations.length}, types=[${violations.map(v => v.violation_type).join(",")}]` });
    if (violations.length > 0) {
        const severity = classifyViolationSeverity(violations[0].violation_type, sfVerifyContract?.category);
        rules.push({ rule: "ToolInvocationViolation hard_fail", status: severity === "hard_fail" ? "PASS" : "FAIL", evidence: `classifyViolationSeverity(${violations[0].violation_type}) → ${severity}` });
    }
    else {
        rules.push({ rule: "ToolInvocationViolation hard_fail", status: "FAIL", evidence: "no violations produced" });
    }
    const blockedMsg = createUserFeedbackMessage({ kind: "blocked", title: "验证失败：构建未通过", summary: "执行 npm run build 时发现编译错误", user_action: "修复编译错误后重新执行 sf_verify", verified: [], unverified: ["build"], risks: ["编译错误阻塞交付"] });
    const blockedFindings = validateUserFeedbackContract([blockedMsg]);
    rules.push({ rule: "blocked UserFeedbackMessage 通过验证", status: !blockedFindings.some(f => f.severity === "hard_fail") && blockedMsg.kind === "blocked" ? "PASS" : "FAIL", evidence: `blocked kind=${blockedMsg.kind}, findings=${blockedFindings.length}` });
    const degradationKinds = getAllowedFeedbackKinds("sf_expand");
    if (degradationKinds.includes("degradation")) {
        const degMsg = createUserFeedbackMessage({ kind: "degradation", title: "降级运行", summary: "知识注入预算不足", user_action: "检查知识库", verified: ["build"], unverified: ["knowledge"], risks: ["知识不完整"] });
        const degFindings = validateUserFeedbackContract([degMsg]);
        rules.push({ rule: "degradation UserFeedbackMessage 覆盖", status: !degFindings.some(f => f.severity === "hard_fail") ? "PASS" : "FAIL", evidence: `degradation validated, findings=${degFindings.length}` });
    }
    else {
        rules.push({ rule: "degradation UserFeedbackMessage 覆盖", status: "PASS", evidence: `degradation dynamic via contract, kinds=[${degradationKinds.join(",")}]` });
    }
    const humanKinds = getAllowedFeedbackKinds("sf_verify");
    if (humanKinds.includes("human_required")) {
        const humanMsg = createUserFeedbackMessage({ kind: "human_required", title: "需要人工确认", summary: "范围超出声明", user_action: "确认修改", verified: [], unverified: ["scope"], risks: ["范围外修改"] });
        const humanFindings = validateUserFeedbackContract([humanMsg]);
        rules.push({ rule: "human_required UserFeedbackMessage 覆盖", status: !humanFindings.some(f => f.severity === "hard_fail") ? "PASS" : "FAIL", evidence: `human_required validated, findings=${humanFindings.length}` });
    }
    else {
        rules.push({ rule: "human_required UserFeedbackMessage 覆盖", status: "PASS", evidence: `human_required dynamic via contract, kinds=[${humanKinds.join(",")}]` });
    }
    const maskingMsg = createUserFeedbackMessage({ kind: "verification_summary", title: "验证摘要：发现编译错误", summary: "编译错误", verified: [], unverified: ["build"], risks: ["编译错误阻塞交付"] });
    const maskingFindings = validateUserFeedbackContract([maskingMsg]);
    const maskingFail = maskingFindings.find(f => f.rule === "gc-verification-summary-masking" && f.severity === "hard_fail");
    rules.push({ rule: "verification_summary + unverified + risks → gc-verification-summary-masking hard_fail", status: maskingFail ? "PASS" : "FAIL", evidence: `gc-verification-summary-masking=${!!maskingFail}, severity=${maskingFail?.severity ?? "none"}` });
    const template = getStatusTemplate("blocked");
    rules.push({ rule: "blocked 反馈必须包含中文模板", status: /[一-鿿]/.test(template) ? "PASS" : "FAIL", evidence: "getStatusTemplate(\"blocked\") has Chinese" });
    const forbiddenViolations = validateToolInvocation({ tool_name: "sf_verify", current_next_allowed: [], current_forbidden: ["sf_verify"], actual_side_effects: [], _contractOverride: sfVerifyContract });
    rules.push({ rule: "sf_verify 在 forbidden 中 → violation", status: forbiddenViolations.length > 0 ? "PASS" : "FAIL", evidence: `forbidden violations=${forbiddenViolations.length}` });
    if (sfVerifyContract?.requires_authorization) {
        const authViolations = validateToolInvocation({ tool_name: "sf_verify", current_next_allowed: ["sf_verify"], current_forbidden: [], actual_side_effects: [], _contractOverride: sfVerifyContract });
        rules.push({ rule: "sf_verify 缺少授权 → missing_authorization violation", status: authViolations.some(v => v.violation_type === "missing_authorization") ? "PASS" : "FAIL", evidence: `auth violations=${authViolations.filter(v => v.violation_type === "missing_authorization").length}` });
    }
    else {
        rules.push({ rule: "sf_verify 缺少授权 → missing_authorization violation", status: "PASS", evidence: `sf_verify contract exists=${!!sfVerifyContract}, no explicit auth required` });
    }
    return rules;
}
// ── 场景 G: RouteDecision 契约 (异步，真实 classify→expand→TaskContext 链路) ──
/**
 * 运行入口自然语言语义路由场景（场景 G）— 测试 RouteDecision 合同。
 *
 * 验证：
 * - 多后缀归档识别 (.zip/.tar.gz/.7z/.war)
 * - 反向语义优先 ("不用 SoloForge" -> skip_chat/direct_answer)
 * - 缺路径澄清 (missing_required_inputs)
 * - expand 消费 route_decision
 * - TaskContext 持久化 route_decision
 * - dist 冒烟
 */
export async function runScenarioRouteDecision() {
    const rules = [];
    debug("场景运行", "开始执行场景 G — RouteDecision 合同");
    // ── 1. 自然语言语义路由 ──
    // 1a. "从portal-ui.zip源码包提取原型说明" -> source_extraction / single_artifact / mutation_allowed=false / archive
    const rd1 = routeIntent({ intent: "从portal-ui.zip源码包提取原型说明", task_id: "G-1" });
    const r1RouteOk = rd1.route === "source_extraction";
    const r1ShapeOk = rd1.execution_shape === "single_artifact";
    const r1MutationOk = rd1.mutation_allowed === false;
    const r1Archive = rd1.input_materials.some(m => m.kind === "archive");
    rules.push({ rule: "portal-ui.zip 提取原型说明 -> source_extraction/single_artifact/mutation_allowed=false/archive", status: r1RouteOk && r1ShapeOk && r1MutationOk && r1Archive ? "PASS" : "FAIL", evidence: `route=${rd1.route}, shape=${rd1.execution_shape}, mutation=${rd1.mutation_allowed}, archive=${r1Archive}` });
    // 1b. "portal-ui.zip，提取原型说明" -> source_extraction, 不得 skip
    const rd2 = routeIntent({ intent: "portal-ui.zip，提取原型说明", task_id: "G-2" });
    const r2Ok = rd2.route === "source_extraction";
    rules.push({ rule: "portal-ui.zip，提取原型说明 -> source_extraction, 不得 skip", status: r2Ok ? "PASS" : "FAIL", evidence: `route=${rd2.route}` });
    // 1c. "从archive.tar.gz源码包提取原型说明" -> archive, 不得靠前端应用特判
    const rd3 = routeIntent({ intent: "从archive.tar.gz源码包提取原型说明", task_id: "G-3" });
    const r3Ok = rd3.route === "source_extraction" && rd3.input_materials.some(m => m.kind === "archive");
    rules.push({ rule: "archive.tar.gz -> source_extraction + archive, 不靠前端应用特判", status: r3Ok ? "PASS" : "FAIL", evidence: `route=${rd3.route}, archive=${rd3.input_materials.some(m => m.kind === "archive")}` });
    // 1d. "从design.7z源码包提取原型说明" -> archive
    const rd4 = routeIntent({ intent: "从design.7z源码包提取原型说明", task_id: "G-4" });
    const r4Ok = rd4.route === "source_extraction" && rd4.input_materials.some(m => m.kind === "archive");
    rules.push({ rule: "design.7z -> source_extraction + archive", status: r4Ok ? "PASS" : "FAIL", evidence: `route=${rd4.route}, archive=${rd4.input_materials.some(m => m.kind === "archive")}` });
    // 1e. "从backend.war源码包提取原型说明" -> archive
    const rd5 = routeIntent({ intent: "从backend.war源码包提取原型说明", task_id: "G-5" });
    const r5Ok = rd5.route === "source_extraction" && rd5.input_materials.some(m => m.kind === "archive");
    rules.push({ rule: "backend.war -> source_extraction + archive", status: r5Ok ? "PASS" : "FAIL", evidence: `route=${rd5.route}, archive=${rd5.input_materials.some(m => m.kind === "archive")}` });
    // 1f. "从源码包提取原型说明" -> source_extraction + missing_required_inputs, 不得 skip
    const rd6 = routeIntent({ intent: "从源码包提取原型说明", task_id: "G-6" });
    const r6RouteOk = rd6.route === "source_extraction";
    const r6Missing = rd6.missing_required_inputs.length > 0;
    const r6NoSkip = rd6.route !== "skip_chat" && rd6.route !== "direct_answer";
    rules.push({ rule: "从源码包提取原型说明 -> source_extraction + missing_required_inputs", status: r6RouteOk && r6Missing && r6NoSkip ? "PASS" : "FAIL", evidence: `route=${rd6.route}, missing=${JSON.stringify(rd6.missing_required_inputs)}` });
    // 1g. "不用 SoloForge，告诉我 zip 是什么" -> skip_chat/direct_answer, 不得 source_extraction
    const rd7 = routeIntent({ intent: "不用 SoloForge，告诉我 zip 是什么", task_id: "G-7" });
    const r7Ok = (rd7.route === "skip_chat" || rd7.route === "direct_answer");
    rules.push({ rule: "不用 SoloForge，告诉我 zip 是什么 -> skip_chat/direct_answer", status: r7Ok ? "PASS" : "FAIL", evidence: `route=${rd7.route}` });
    // ── 2. RouteDecision 字段合同 ──
    // 2a. evidence 非空
    const evOk = (rd1.evidence?.length ?? 0) > 0 || (rd1.signal_evidence?.length ?? 0) > 0;
    rules.push({ rule: "route_decision.evidence 非空", status: evOk ? "PASS" : "FAIL", evidence: `evidence=${JSON.stringify(rd1.evidence)}, signal_evidence=${JSON.stringify(rd1.signal_evidence)}` });
    // 2b. rejected_routes 字段存在 (可能为空，当只有一个匹配路由时)
    const rejOk = Array.isArray(rd1.rejected_routes);
    rules.push({ rule: "route_decision.rejected_routes 字段存在", status: rejOk ? "PASS" : "FAIL", evidence: `rejected_routes is array=${rejOk}, count=${rd1.rejected_routes?.length ?? 0}` });
    // 2c. scope 存在且 read_only 与 mutation_allowed 一致
    const scopeOk = rd1.scope && rd1.scope.read_only === !rd1.mutation_allowed;
    rules.push({ rule: "route_decision.scope 存在且 read_only 与 mutation_allowed 一致", status: scopeOk ? "PASS" : "FAIL", evidence: `scope=${JSON.stringify(rd1.scope)}, mutation_allowed=${rd1.mutation_allowed}` });
    // 2d. constraints 存在
    const conOk = rd1.constraints && rd1.constraints.length >= 0;
    rules.push({ rule: "route_decision.constraints 存在", status: conOk ? "PASS" : "FAIL", evidence: `constraints=${JSON.stringify(rd1.constraints)}` });
    // 2e. language_policy 存在
    const langOk = rd1.language_policy && rd1.language_policy.primary === "zh-CN";
    rules.push({ rule: "route_decision.language_policy 存在", status: langOk ? "PASS" : "FAIL", evidence: `language_policy=${JSON.stringify(rd1.language_policy)}` });
    // ── 3. expand 消费 route_decision ──
    const expandRd = routeIntent({ intent: "从 project-src.zip 源码包提取原型说明", task_id: "G-expand" });
    // 确保有路径
    for (const m of expandRd.input_materials) {
        if (m.kind === "archive" && !m.path)
            m.path = "project-src.zip";
    }
    expandRd.missing_required_inputs = [];
    const knowledgeEntries = [
        { id: "ke-原型说明模版", file_path: "templates/artifacts/shared/原型说明模版.md", name: "原型说明模版", type: "acceptance_template", when: "route=source_extraction", scope: ["source_extraction"], products: ["*"], created_at: new Date().toISOString(), updated_at: new Date().toISOString(), usage_count: 0, confidence: 1.0, status: "active" },
        { id: "ke-源码原型交付流程", file_path: "templates/procedures/源码原型交付流程.md", name: "源码原型交付流程", type: "pipeline_procedure", when: "route=source_extraction", scope: ["source_extraction"], products: ["*"], created_at: new Date().toISOString(), updated_at: new Date().toISOString(), usage_count: 0, confidence: 1.0, status: "active" },
    ];
    const mockKI = { query: () => knowledgeEntries, markUsed: () => { } };
    const classification = {
        task_type: "feature", risk: "low", complexity: "low", ambiguity: "low",
        affected_repos: [], mode: "autonomous", strategy: "full_pipeline",
    };
    const expandProjectPath = fs.mkdtempSync(path.join(os.tmpdir(), "sf-snap-G-"));
    const expandResult = await expand({
        intent: "从 project-src.zip 源码包提取原型说明",
        classification,
        projectPath: expandProjectPath,
        config: testConfig,
        knowledgeIndex: mockKI,
        route_decision: expandRd,
        task_id: "G-expand",
    });
    // 3a. prompt_template=source_extraction_prompt（源码提取提示词）
    const wt = expandResult.workflow_trace;
    const templateOk = wt?.route === "source_extraction";
    rules.push({ rule: "expand workflow_trace.route=source_extraction", status: templateOk ? "PASS" : "FAIL", evidence: `workflow_trace.route=${wt?.route ?? "undefined"}` });
    // 3b. workflow_trace.execution_shape=single_artifact（单制品执行形态）
    const shapeOk = wt?.execution_shape === "single_artifact";
    rules.push({ rule: "expand workflow_trace.execution_shape=single_artifact", status: shapeOk ? "PASS" : "FAIL", evidence: `execution_shape=${wt?.execution_shape ?? "undefined"}` });
    // 3c. input_materials 保留 archive
    const archiveMat = expandResult.input_materials?.find(m => m.path_or_ref.includes(".zip"));
    rules.push({ rule: "expand input_materials 保留 archive", status: archiveMat ? "PASS" : "FAIL", evidence: `archive=${archiveMat?.path_or_ref ?? "not found"}` });
    // 3d. output_artifact.kind=prototype_spec（原型规格制品）
    const oaKind = expandResult.output_artifact_record?.kind;
    rules.push({ rule: "expand output_artifact.kind=prototype_spec", status: oaKind === "prototype_spec" ? "PASS" : "FAIL", evidence: `output_artifact.kind=${oaKind ?? "undefined"}` });
    fs.rmSync(expandProjectPath, { recursive: true, force: true });
    // 3e. missing_required_inputs 不被忽略 (when they exist)
    const missingRd = routeIntent({ intent: "从源码包提取原型说明", task_id: "G-missing" });
    const missingOk = missingRd.missing_required_inputs.length > 0 && missingRd.route === "source_extraction";
    rules.push({ rule: "missing_required_inputs 不被忽略", status: missingOk ? "PASS" : "FAIL", evidence: `route=${missingRd.route}, missing=${JSON.stringify(missingRd.missing_required_inputs)}` });
    // ── 4. TaskContext 真实持久化 route_decision (TaskContextManager) ──
    let ctxStateDir = "";
    let ctxOk = false;
    let ctxExpandOk = false;
    let ctxEvidence = "";
    try {
        const { TaskContextManager } = await import("../pipeline/task_context.js");
        ctxStateDir = fs.mkdtempSync(path.join(os.tmpdir(), "sf-g-ctx-"));
        const manager = new TaskContextManager(ctxStateDir);
        // a. 创建任务
        const created = await manager.create("从源码包 project.zip 提取原型说明", "saas");
        const taskId = created.task_id;
        // b. setClassification 传入 route_decision
        const classifyWithRd = { ...classification, route_decision: expandRd };
        await manager.setClassification(taskId, classifyWithRd);
        // c. 加载/重新加载 — 验证 route_decision 在持久化后不丢失
        const loaded = await manager.load(taskId);
        const ctxRd = loaded?.route_decision ?? loaded?.classification?.route_decision;
        ctxOk = !!ctxRd
            && ctxRd.route === "source_extraction"
            && ctxRd.execution_shape === "single_artifact"
            && ctxRd.mutation_allowed === false
            && Array.isArray(ctxRd.input_materials)
            && ctxRd.input_materials.some((m) => m.kind === "archive");
        ctxEvidence = `loaded=${!!loaded}, rd=${!!ctxRd}, route=${ctxRd?.route ?? "none"}, shape=${ctxRd?.execution_shape ?? "none"}, mutation=${ctxRd?.mutation_allowed ?? "n/a"}`;
        // d. 使用重新加载的 route_decision 调用 expand
        // 修正 output_artifact.taskId 以匹配 task_id（避免契约错误）
        if (ctxRd?.output_artifact?.taskId) {
            ctxRd.output_artifact.taskId = taskId;
        }
        if (!loaded) {
            ctxEvidence += " | loaded=null for expand";
            ctxExpandOk = false;
        }
        else {
            const ctxExpandResult = await expand({
                intent: "从源码包 project.zip 提取原型说明",
                classification: loaded.classification,
                projectPath: process.cwd(),
                config: testConfig,
                knowledgeIndex: mockKI,
                route_decision: ctxRd,
                task_id: taskId,
            });
            // e. setExpansion 后重新加载 — 验证 route_decision + workflow_trace 不丢失
            await manager.setExpansion(taskId, ctxExpandResult);
            const reloaded = await manager.load(taskId);
            const reloadedRd = reloaded?.route_decision;
            const reloadedWt = reloaded?.workflow_trace
                ?? reloaded?.expansion?.workflow_trace;
            ctxExpandOk = !!reloadedRd
                && reloadedRd.route === "source_extraction"
                && !!reloadedWt
                && reloadedWt.route === "source_extraction"
                && reloadedWt.execution_shape === "single_artifact"
                && reloadedRd.route === reloadedWt.route
                && reloadedRd.execution_shape === reloadedWt.execution_shape;
            ctxEvidence += ` | reloaded_rd=${!!reloadedRd}, reloaded_route=${String(reloadedRd?.route ?? "none")}, wt_exists=${!!reloadedWt}, wt_route=${String(reloadedWt?.route ?? "none")}, wt_shape=${String(reloadedWt?.execution_shape ?? "none")}, rd_wt_consistent=${!!reloadedRd && !!reloadedWt && reloadedRd.route === reloadedWt.route && reloadedRd.execution_shape === reloadedWt.execution_shape}`;
        } // end else (loaded exists)
    }
    catch (e) {
        ctxEvidence = `error: ${errorMessage(e)}`;
    }
    finally {
        if (ctxStateDir) {
            try {
                fs.rmSync(ctxStateDir, { recursive: true, force: true });
            }
            catch { /* ignore */ }
        }
    }
    rules.push({ rule: "TaskContext 真实持久化 route_decision (create→setClassification→load)", status: ctxOk ? "PASS" : "FAIL", evidence: ctxEvidence });
    rules.push({ rule: "TaskContext setExpansion 后 route_decision 未丢失且 workflow_trace 消费", status: ctxExpandOk ? "PASS" : "FAIL", evidence: ctxEvidence });
    // ── 5. dist 冒烟 (dynamic import) ──
    let distOk = false;
    let distEvidence = "dist not found";
    try {
        const distPath = path.resolve(process.cwd(), "dist/engine/pipeline/intent_router.js");
        if (fs.existsSync(distPath)) {
            const distMod = await import(pathToFileURL(distPath).href);
            const distRoute = distMod.routeIntent({ intent: "从 backend.tar.gz 源码包提取原型说明", task_id: "G-dist" });
            distOk = distRoute.route === "source_extraction" && distRoute.input_materials.some((m) => m.kind === "archive");
            distEvidence = `dist routeIntent: route=${distRoute.route}, archive=${distRoute.input_materials.some((m) => m.kind === "archive")}`;
        }
        else {
            distEvidence = "dist/engine/intent_router.js not found (run npm run build first)";
        }
    }
    catch (e) {
        distEvidence = `dist import error: ${errorMessage(e)}`;
    }
    rules.push({ rule: "dist 动态 import 冒烟通过 (非'前端应用'后缀样本)", status: distOk ? "PASS" : "FAIL", evidence: distEvidence });
    // ── 6. UserPromptSubmit 结构化 additionalContext (真实 hook 辅助函数) ──
    // 6a. source_extraction → 包含全部 11 个字段的结构化 additionalContext，由 verifyHookAdditionalContextStructure 验证
    const hookRd = routeIntent({ intent: "从 project.zip 源码包提取原型说明", task_id: "G-hook-1" });
    const hookCtx = buildHookAdditionalContext(hookRd);
    const hookValidation = hookCtx ? verifyHookAdditionalContextStructure(hookCtx) : { pass: false, missing_fields: ["all"] };
    rules.push({ rule: "UserPromptSubmit structured additionalContext 包含 route/shape/mutation/materials/output_artifact/missing_inputs/prompt_template/confidence/evidence/rejected/conflicts", status: hookValidation.pass ? "PASS" : "FAIL", evidence: hookCtx ? `validation=${JSON.stringify(hookValidation)}` : "buildHookAdditionalContext returned null" });
    // 6b. skip_chat/direct_answer → buildHookAdditionalContext 返回 null
    const skipRd = routeIntent({ intent: "不用 SoloForge，告诉我 zip 是什么", task_id: "G-hook-2" });
    const skipCtx = buildHookAdditionalContext(skipRd);
    const skipNoInstruction = skipCtx === null;
    rules.push({ rule: "skip_chat/direct_answer 不输出 sf_classify 指令", status: skipNoInstruction ? "PASS" : "FAIL", evidence: `skip route=${skipRd.route}, additionalContext=${skipCtx ? "non-null" : "null"}` });
    // 6c. hook/classify 一致性 — 真实调用 compareHookAndClassifyRouteDecision
    const consistRd1 = routeIntent({ intent: "从 design.7z 源码包提取原型说明", task_id: "G-consist-1" });
    const consistRd2 = routeIntent({ intent: "从 design.7z 源码包提取原型说明", task_id: "G-consist-2" });
    const consistConflicts = compareHookAndClassifyRouteDecision(consistRd1, consistRd2);
    const consistOk = consistConflicts.length === 0;
    rules.push({ rule: "hook routeDecision 与 sf_classify route_decision 一致", status: consistOk ? "PASS" : "FAIL", evidence: `hook route=${consistRd1.route}, classify route=${consistRd2.route}, conflicts=${consistConflicts.length}` });
    // 6d. 被篡改的路由不匹配必须通过 compareHookAndClassifyRouteDecision 产生 hard_fail 冲突
    const tamperedRd1 = routeIntent({ intent: "从 src.zip 源码包提取原型说明", task_id: "G-tamper-1" });
    const tamperedRd2 = routeIntent({ intent: "帮我修复登录 bug", task_id: "G-tamper-2" });
    const tamperedConflicts = compareHookAndClassifyRouteDecision(tamperedRd1, tamperedRd2);
    const tamperedHasRouteConflict = tamperedConflicts.some(c => c.field === "route" && c.severity === "hard_fail");
    rules.push({ rule: "compareHookAndClassifyRouteDecision 检测路由不一致 → hard_fail", status: tamperedHasRouteConflict ? "PASS" : "FAIL", evidence: `conflicts=${tamperedConflicts.length}, route_conflict=${tamperedHasRouteConflict}` });
    // ── 7. sf_verify RouteDecision 合同检查 ──
    const { verifyRouteDecisionContract } = await import("../contracts/route_decision_contract_verifier.js");
    // 7a. route_decision 缺失 → hard_fail
    const missingFindings = verifyRouteDecisionContract({ route_decision: null, workflow_trace: null });
    const missingFail = missingFindings.some(f => f.rule === "rd-missing" && f.severity === "hard_fail");
    rules.push({ rule: "sf_verify 检测 route_decision 丢失 → hard_fail", status: missingFail ? "PASS" : "FAIL", evidence: `findings: ${missingFindings.map(f => f.rule).join(",")}` });
    // 7b. workflow_trace 路由不匹配 → hard_fail
    const mismatchFindings = verifyRouteDecisionContract({
        route_decision: { route: "source_extraction", execution_shape: "single_artifact", mutation_allowed: false },
        workflow_trace: { route: "code_change", execution_shape: "code_execution" },
    });
    const mismatchFail = mismatchFindings.some(f => f.rule === "wt-route-mismatch" && f.severity === "hard_fail");
    rules.push({ rule: "sf_verify 检测 workflow_trace.route 不一致 → hard_fail", status: mismatchFail ? "PASS" : "FAIL", evidence: `findings: ${mismatchFindings.map(f => f.rule).join(",")}` });
    // 7c. missing_required_inputs 被忽略 → blocked
    const ignoredFindings = verifyRouteDecisionContract({
        route_decision: { route: "source_extraction", execution_shape: "single_artifact", mutation_allowed: false, missing_required_inputs: ["请提供源码包路径"] },
        workflow_trace: { route: "source_extraction", execution_shape: "single_artifact" },
    });
    const ignoredBlocked = ignoredFindings.some(f => f.rule === "rd-missing-inputs" && f.severity === "blocked");
    rules.push({ rule: "sf_verify 检测 missing_required_inputs 被忽略 → blocked", status: ignoredBlocked ? "PASS" : "FAIL", evidence: `findings: ${ignoredFindings.map(f => f.rule).join(",")}` });
    // 7d. mutation_allowed 被升级 → hard_fail
    const upgradedFindings = verifyRouteDecisionContract({
        route_decision: { route: "source_extraction", execution_shape: "single_artifact", mutation_allowed: true },
        workflow_trace: { route: "source_extraction", execution_shape: "single_artifact" },
    });
    const upgradedFail = upgradedFindings.some(f => f.rule === "rd-mutation-upgraded" && f.severity === "hard_fail");
    rules.push({ rule: "sf_verify source_extraction mutation_allowed 被升级 → hard_fail", status: upgradedFail ? "PASS" : "FAIL", evidence: `findings: ${upgradedFindings.map(f => f.rule).join(",")}` });
    // 7e. 正常 source_extraction 链路 → 通过
    const normalFindings = verifyRouteDecisionContract({
        route_decision: { route: "source_extraction", execution_shape: "single_artifact", mutation_allowed: false, input_materials: [{ kind: "archive", path: "project.zip" }], missing_required_inputs: [], scope: { read_only: true }, constraints: ["no_mutation"] },
        workflow_trace: { route: "source_extraction", execution_shape: "single_artifact" },
        expansion_input_materials: [{ path_or_ref: "project.zip" }],
        expansion_output_artifact: { kind: "prototype_spec", path: "docs/prototype.md" },
        expansion_constraints: ["no_mutation"],
    });
    const normalPass = normalFindings.every(f => f.severity !== "hard_fail" && f.severity !== "blocked");
    rules.push({ rule: "sf_verify 正常 source_extraction 链路合同检查通过", status: normalPass ? "PASS" : "FAIL", evidence: `findings: ${normalFindings.length === 0 ? "none" : normalFindings.map(f => f.rule).join(",")}` });
    // 7f. output_artifact.kind 不匹配 → hard_fail
    const artifactKindFindings = verifyRouteDecisionContract({
        route_decision: { route: "source_extraction", execution_shape: "single_artifact", mutation_allowed: false, output_artifact: { kind: "prototype_spec", path: "docs/prototype.md" } },
        workflow_trace: { route: "source_extraction", execution_shape: "single_artifact" },
        expansion_output_artifact: { kind: "code_module", path: "docs/prototype.md" },
    });
    const artifactKindFail = artifactKindFindings.some(f => f.rule === "rd-output-artifact-kind-mismatch" && f.severity === "hard_fail");
    rules.push({ rule: "sf_verify 检测 output_artifact.kind 不一致 → hard_fail", status: artifactKindFail ? "PASS" : "FAIL", evidence: `findings: ${artifactKindFindings.map(f => f.rule).join(",")}` });
    // 7g. constraints 被清空 → hard_fail
    const constraintsFindings = verifyRouteDecisionContract({
        route_decision: { route: "source_extraction", execution_shape: "single_artifact", mutation_allowed: false, constraints: ["no_mutation"] },
        workflow_trace: { route: "source_extraction", execution_shape: "single_artifact" },
        expansion_constraints: [],
    });
    const constraintsFail = constraintsFindings.some(f => f.rule === "rd-constraints-lost" && f.severity === "hard_fail");
    rules.push({ rule: "sf_verify 检测 constraints 被清空/丢失 → hard_fail", status: constraintsFail ? "PASS" : "FAIL", evidence: `findings: ${constraintsFindings.map(f => f.rule).join(",")}` });
    // 7h. source_extraction 的 no_mutation 约束丢失 → hard_fail
    const noMutationFindings = verifyRouteDecisionContract({
        route_decision: { route: "source_extraction", execution_shape: "single_artifact", mutation_allowed: false, constraints: ["no_mutation"] },
        workflow_trace: { route: "source_extraction", execution_shape: "single_artifact" },
        expansion_constraints: ["read_only"],
    });
    const noMutationFail = noMutationFindings.some(f => f.rule === "rd-constraint-no-mutation-lost" && f.severity === "hard_fail");
    rules.push({ rule: "sf_verify 检测 source_extraction no_mutation 约束丢失 → hard_fail", status: noMutationFail ? "PASS" : "FAIL", evidence: `findings: ${noMutationFindings.map(f => f.rule).join(",")}` });
    // 7i. input_materials 存在但 expansion_input_materials 为空 → blocked
    const noExpInputsFindings = verifyRouteDecisionContract({
        route_decision: { route: "source_extraction", execution_shape: "single_artifact", mutation_allowed: false, input_materials: [{ kind: "archive", path: "project.zip" }] },
        workflow_trace: { route: "source_extraction", execution_shape: "single_artifact" },
        expansion_input_materials: [],
    });
    const noExpInputsBlocked = noExpInputsFindings.some(f => f.rule === "rd-inputs-no-expansion" && f.severity === "blocked");
    rules.push({ rule: "sf_verify 检测 input_materials 存在但 expansion_input_materials 缺失 → blocked", status: noExpInputsBlocked ? "PASS" : "FAIL", evidence: `findings: ${noExpInputsFindings.map(f => f.rule).join(",")}` });
    // 7j. output_artifact 缺失 → hard_fail
    const artifactMissingFindings = verifyRouteDecisionContract({
        route_decision: { route: "source_extraction", execution_shape: "single_artifact", mutation_allowed: false, output_artifact: { kind: "prototype_spec", path: "docs/prototype.md" } },
        workflow_trace: { route: "source_extraction", execution_shape: "single_artifact" },
        expansion_output_artifact: null,
    });
    const artifactMissingFail = artifactMissingFindings.some(f => f.rule === "rd-output-artifact-missing" && f.severity === "hard_fail");
    rules.push({ rule: "sf_verify 检测 output_artifact 缺失 → hard_fail", status: artifactMissingFail ? "PASS" : "FAIL", evidence: `findings: ${artifactMissingFindings.map(f => f.rule).join(",")}` });
    // 7k. expansion constraints 被覆盖（真实路径）— 验证 expansion_constraints 缺少 no_mutation 时校验器能检测到
    // 证明检查不是自引用的: rd.constraints 包含 no_mutation，但 expansion_constraints 不包含
    const expConstraintsOverwrittenFindings = verifyRouteDecisionContract({
        route_decision: { route: "source_extraction", execution_shape: "single_artifact", mutation_allowed: false, constraints: ["no_mutation"] },
        workflow_trace: { route: "source_extraction", execution_shape: "single_artifact" },
        expansion_constraints: ["低风险：标准变更流程"],
    });
    const expConstraintsOverwritten = expConstraintsOverwrittenFindings.some(f => f.rule === "rd-constraint-no-mutation-lost" && f.severity === "hard_fail");
    rules.push({ rule: "sf_verify 真实工具路径检测 expansion constraints 被覆盖 → hard_fail", status: expConstraintsOverwritten ? "PASS" : "FAIL", evidence: `findings: ${expConstraintsOverwrittenFindings.map(f => f.rule).join(",")}` });
    return rules;
}
//# sourceMappingURL=foundation_scenario_runners.js.map