soloforge 1.4.10 → 1.4.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/claude_code/tools.d.ts +3 -0
- package/dist/adapters/claude_code/tools.d.ts.map +1 -1
- package/dist/adapters/claude_code/tools.js +119 -182
- package/dist/adapters/claude_code/tools.js.map +1 -1
- package/dist/engine/brainstorm_contract.d.ts +2 -0
- package/dist/engine/brainstorm_contract.d.ts.map +1 -1
- package/dist/engine/brainstorm_contract.js +11 -1
- package/dist/engine/brainstorm_contract.js.map +1 -1
- package/dist/engine/expand_pipeline.d.ts +121 -0
- package/dist/engine/expand_pipeline.d.ts.map +1 -0
- package/dist/engine/expand_pipeline.js +141 -0
- package/dist/engine/expand_pipeline.js.map +1 -0
- package/dist/engine/first_principles.d.ts +2 -0
- package/dist/engine/first_principles.d.ts.map +1 -1
- package/dist/engine/first_principles.js +14 -1
- package/dist/engine/first_principles.js.map +1 -1
- package/dist/engine/intent_expander.d.ts +3 -0
- package/dist/engine/intent_expander.d.ts.map +1 -1
- package/dist/engine/intent_expander.js +252 -306
- package/dist/engine/intent_expander.js.map +1 -1
- package/dist/engine/intent_route_scorer.d.ts +1 -1
- package/dist/engine/intent_route_scorer.d.ts.map +1 -1
- package/dist/engine/intent_route_scorer.js +18 -3
- package/dist/engine/intent_route_scorer.js.map +1 -1
- package/dist/engine/intent_router.d.ts +2 -2
- package/dist/engine/intent_router.d.ts.map +1 -1
- package/dist/engine/intent_router.js +28 -6
- package/dist/engine/intent_router.js.map +1 -1
- package/dist/engine/intent_signal_extractor.d.ts +1 -1
- package/dist/engine/intent_signal_extractor.d.ts.map +1 -1
- package/dist/engine/intent_signal_extractor.js +12 -0
- package/dist/engine/intent_signal_extractor.js.map +1 -1
- package/dist/engine/release_readiness_gate.d.ts.map +1 -1
- package/dist/engine/release_readiness_gate.js +38 -37
- package/dist/engine/release_readiness_gate.js.map +1 -1
- package/dist/engine/source_code_matcher.d.ts +53 -0
- package/dist/engine/source_code_matcher.d.ts.map +1 -0
- package/dist/engine/source_code_matcher.js +165 -0
- package/dist/engine/source_code_matcher.js.map +1 -0
- package/dist/engine/task_context.d.ts +5 -0
- package/dist/engine/task_context.d.ts.map +1 -1
- package/dist/engine/task_context.js +37 -5
- package/dist/engine/task_context.js.map +1 -1
- package/dist/engine/technology_decision.d.ts +2 -0
- package/dist/engine/technology_decision.d.ts.map +1 -1
- package/dist/engine/technology_decision.js +18 -1
- package/dist/engine/technology_decision.js.map +1 -1
- package/dist/engine/traceability.d.ts.map +1 -1
- package/dist/engine/traceability.js +4 -0
- package/dist/engine/traceability.js.map +1 -1
- package/dist/engine/workflow_contract_registry.d.ts.map +1 -1
- package/dist/engine/workflow_contract_registry.js +24 -0
- package/dist/engine/workflow_contract_registry.js.map +1 -1
- package/dist/knowledge/index_manager.d.ts +1 -0
- package/dist/knowledge/index_manager.d.ts.map +1 -1
- package/dist/knowledge/index_manager.js +15 -0
- package/dist/knowledge/index_manager.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -33,6 +33,7 @@ import { validateBrainstormSession } from "./brainstorm_contract.js";
|
|
|
33
33
|
import { resolveTaskScope } from "./scope_resolver.js";
|
|
34
34
|
import { evaluateLifecycleKnowledgeDecision } from "./lifecycle_knowledge_contract.js";
|
|
35
35
|
import { extractTraceabilityIds } from "./traceability.js";
|
|
36
|
+
import { createExpandRoutePhasePolicy } from "./expand_pipeline.js";
|
|
36
37
|
// 配置优先级:委托给 resolveCurrentProjectConfigReports (shared function)
|
|
37
38
|
// ── 产物类型映射 ──
|
|
38
39
|
function mapToArtifactKind(kind) {
|
|
@@ -246,7 +247,42 @@ const READ_ONLY_ANALYSIS_TEMPLATE = Handlebars.compile(`## 任务
|
|
|
246
247
|
- 标注风险和假设
|
|
247
248
|
- 给出建议(如有)
|
|
248
249
|
`);
|
|
249
|
-
// 5.
|
|
250
|
+
// 5. acceptance_prompt: 验收/就绪检查,不修改源码
|
|
251
|
+
const ACCEPTANCE_TEMPLATE = Handlebars.compile(`## 任务
|
|
252
|
+
{{intent}}
|
|
253
|
+
|
|
254
|
+
## 工作流: 验收/就绪检查
|
|
255
|
+
- 这是只读检查路径,不修改业务源码,不生成脚手架,不创建实现文件
|
|
256
|
+
- 目标是判断列出的事项是否就绪、通过、满足条件或仍需处理
|
|
257
|
+
- 只输出检查结论、证据、阻塞项和下一步建议
|
|
258
|
+
|
|
259
|
+
## 项目上下文
|
|
260
|
+
- 技术栈: {{tech_stack}}
|
|
261
|
+
- 产品类型: {{product_profile}}
|
|
262
|
+
|
|
263
|
+
{{#if matched_knowledge}}
|
|
264
|
+
## 适用知识
|
|
265
|
+
{{#each matched_knowledge}}
|
|
266
|
+
### {{this.name}}
|
|
267
|
+
{{this.content}}
|
|
268
|
+
|
|
269
|
+
{{/each}}
|
|
270
|
+
{{/if}}
|
|
271
|
+
|
|
272
|
+
## 检查要求
|
|
273
|
+
- 对每一项给出: passed / blocked / unknown
|
|
274
|
+
- blocked 必须说明阻塞原因和可执行恢复动作
|
|
275
|
+
- unknown 必须说明缺少哪些证据
|
|
276
|
+
- 不要求技术决策契约、架构决策研讨、OOD/SOLID 摘要或代码可观测性工作包
|
|
277
|
+
|
|
278
|
+
{{#if acceptance.automated}}
|
|
279
|
+
## 验收项
|
|
280
|
+
{{#each acceptance.automated}}
|
|
281
|
+
- [{{this.id}}] {{this.description}}
|
|
282
|
+
{{/each}}
|
|
283
|
+
{{/if}}
|
|
284
|
+
`);
|
|
285
|
+
// 6. verification_only_prompt: 验证命令生成,不修改源码
|
|
250
286
|
const VERIFICATION_ONLY_TEMPLATE = Handlebars.compile(`## 任务
|
|
251
287
|
{{intent}}
|
|
252
288
|
|
|
@@ -506,6 +542,35 @@ function renderPromptInjectionPlan(plan) {
|
|
|
506
542
|
}
|
|
507
543
|
return sections.length > 0 ? "---\n\n" + sections.join("\n\n") : "";
|
|
508
544
|
}
|
|
545
|
+
function buildBlockedResult(prompt, safeGoal, options) {
|
|
546
|
+
return {
|
|
547
|
+
task_id: "",
|
|
548
|
+
prompt,
|
|
549
|
+
scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
|
|
550
|
+
acceptance: { automated: [], manual: [] },
|
|
551
|
+
matched_patterns: [],
|
|
552
|
+
matched_knowledge: [],
|
|
553
|
+
is_legacy_code: false,
|
|
554
|
+
degraded: true,
|
|
555
|
+
...(options.sensitivityLabels?.length ? { sensitivity_labels: options.sensitivityLabels } : {}),
|
|
556
|
+
...(options.redactionRecords?.length ? { redaction_records: options.redactionRecords } : {}),
|
|
557
|
+
...(options.privacyFindings?.length ? { privacy_findings: options.privacyFindings } : {}),
|
|
558
|
+
...(options.inputMaterials ? { input_materials: options.inputMaterials } : {}),
|
|
559
|
+
...(options.ingestionEvidences ? { ingestion_evidences: options.ingestionEvidences } : {}),
|
|
560
|
+
...(options.promptInjectionPlan ? { prompt_injection_plan: options.promptInjectionPlan } : {}),
|
|
561
|
+
...(options.outputArtifactRecord ? { output_artifact_record: options.outputArtifactRecord } : {}),
|
|
562
|
+
...(options.injectionReport ? { injection_report: options.injectionReport } : {}),
|
|
563
|
+
...(options.projectKnowledge ? { project_knowledge: options.projectKnowledge } : {}),
|
|
564
|
+
...(options.workflowTrace ? { workflow_trace: options.workflowTrace } : {}),
|
|
565
|
+
contract: {
|
|
566
|
+
goal: safeGoal,
|
|
567
|
+
scope: [],
|
|
568
|
+
constraints: options.constraints,
|
|
569
|
+
verification: [],
|
|
570
|
+
stop_conditions: options.stopConditions,
|
|
571
|
+
},
|
|
572
|
+
};
|
|
573
|
+
}
|
|
509
574
|
/**
|
|
510
575
|
* 根据执行形态选择 prompt 模板。
|
|
511
576
|
* 模板使用独立工作流专属模板,包含对应约束注入。
|
|
@@ -515,6 +580,7 @@ function chooseTemplate(templateName) {
|
|
|
515
580
|
case "single_artifact_prompt": return SINGLE_ARTIFACT_TEMPLATE;
|
|
516
581
|
case "source_extraction_prompt": return SOURCE_EXTRACTION_TEMPLATE;
|
|
517
582
|
case "read_only_analysis_prompt": return READ_ONLY_ANALYSIS_TEMPLATE;
|
|
583
|
+
case "acceptance_prompt": return ACCEPTANCE_TEMPLATE;
|
|
518
584
|
case "verification_only_prompt": return VERIFICATION_ONLY_TEMPLATE;
|
|
519
585
|
case "direct_answer_prompt": return DIRECT_ANSWER_TEMPLATE;
|
|
520
586
|
case "architecture_design_prompt": return ARCHITECTURE_DESIGN_TEMPLATE;
|
|
@@ -593,6 +659,12 @@ export async function expand(input) {
|
|
|
593
659
|
const { intent, classification, projectPath, config, knowledgeIndex } = input;
|
|
594
660
|
let routeDecision = input.route_decision ?? classification.route_decision;
|
|
595
661
|
const templateName = routeDecision ? selectPromptTemplate(routeDecision) : "code_execution_prompt";
|
|
662
|
+
const phasePolicy = createExpandRoutePhasePolicy(routeDecision);
|
|
663
|
+
const skipWorkflowContractStrict = phasePolicy.skip_workflow_contract_strict;
|
|
664
|
+
const skipInputMaterialHardBlock = phasePolicy.skip_input_material_hard_block;
|
|
665
|
+
const skipProjectKnowledgeHardBlock = phasePolicy.skip_project_knowledge_hard_block;
|
|
666
|
+
const skipHeavyContractGates = phasePolicy.skip_heavy_contract_gates;
|
|
667
|
+
const skipPreImplementationGates = phasePolicy.skip_pre_implementation_gates;
|
|
596
668
|
// 配置优先级解析 — 使用共享函数
|
|
597
669
|
let configResolution;
|
|
598
670
|
try {
|
|
@@ -608,36 +680,30 @@ export async function expand(input) {
|
|
|
608
680
|
routeDecision = resolveClarificationAnswers(routeDecision, intent, input.clarificationAnswers);
|
|
609
681
|
}
|
|
610
682
|
// ── Privacy gate— 提前到所有 early-return 之前 ──
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
683
|
+
// 轻量路径(acceptance/review/read_only)只做基础脱敏,跳过深度隐私扫描
|
|
684
|
+
let safeIntent;
|
|
685
|
+
let safeGoal;
|
|
686
|
+
let privacyGate;
|
|
687
|
+
if (phasePolicy.lightweight) {
|
|
688
|
+
safeIntent = redactSensitiveText(intent, "intent").redacted;
|
|
689
|
+
safeGoal = redactSensitiveText(intent.slice(0, 200), "intent_goal").redacted;
|
|
690
|
+
privacyGate = { allowed: true, labels: [], redaction_records: [], findings: [], blocked_sources: [], hard_fail: false };
|
|
691
|
+
}
|
|
692
|
+
else {
|
|
693
|
+
privacyGate = evaluatePrivacyGate({
|
|
694
|
+
intent,
|
|
695
|
+
input_materials: input.route_decision?.input_materials?.map((m) => ({ path_or_ref: m.path ?? "" })) ?? [],
|
|
696
|
+
});
|
|
697
|
+
safeIntent = privacyGate.redacted_text ?? redactSensitiveText(intent, "intent").redacted;
|
|
698
|
+
safeGoal = redactSensitiveText(intent.slice(0, 200), "intent_goal").redacted;
|
|
699
|
+
}
|
|
617
700
|
// 提前创建产物记录 (在所有 early-return 之前),确保所有路径都携带它
|
|
618
701
|
// task_id 为必需 — block if missing
|
|
619
702
|
let outputArtifactRecord;
|
|
620
703
|
if (routeDecision?.output_artifact && routeDecision.execution_shape !== "none" && routeDecision.execution_shape !== "code_execution") {
|
|
621
704
|
const artifactKind = mapToArtifactKind(routeDecision.output_artifact.kind);
|
|
622
705
|
if (!input.task_id) {
|
|
623
|
-
|
|
624
|
-
return {
|
|
625
|
-
task_id: "",
|
|
626
|
-
prompt: `## 阻塞:产物缺少 task_id\n\n任务: ${safeIntent}\n\nexpand() 收到 task_id 为空,无法创建产物记录。`,
|
|
627
|
-
scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
|
|
628
|
-
acceptance: { automated: [], manual: [] },
|
|
629
|
-
matched_patterns: [],
|
|
630
|
-
matched_knowledge: [],
|
|
631
|
-
is_legacy_code: false,
|
|
632
|
-
degraded: true,
|
|
633
|
-
contract: {
|
|
634
|
-
goal: safeGoal,
|
|
635
|
-
scope: [],
|
|
636
|
-
constraints: ["task_id 缺失"],
|
|
637
|
-
verification: [],
|
|
638
|
-
stop_conditions: ["task_id 缺失"],
|
|
639
|
-
},
|
|
640
|
-
};
|
|
706
|
+
return buildBlockedResult(`## 阻塞:产物缺少 task_id\n\n任务: ${safeIntent}\n\nexpand() 收到 task_id 为空,无法创建产物记录。`, safeGoal, { constraints: ["task_id 缺失"], stopConditions: ["task_id 缺失"] });
|
|
641
707
|
}
|
|
642
708
|
// 收集源材料引用 from routeDecision.input_materials
|
|
643
709
|
const sourceMaterialRefs = routeDecision.input_materials
|
|
@@ -645,15 +711,7 @@ export async function expand(input) {
|
|
|
645
711
|
.map((m) => m.path);
|
|
646
712
|
// 冲突时拒绝 with input.task_id
|
|
647
713
|
if (routeDecision.output_artifact.taskId && routeDecision.output_artifact.taskId !== input.task_id) {
|
|
648
|
-
return {
|
|
649
|
-
task_id: input.task_id,
|
|
650
|
-
prompt: `## Contract Error: task_id 不一致\n\nrouteDecision.taskId=${routeDecision.output_artifact.taskId} !== input.task_id=${input.task_id}`,
|
|
651
|
-
scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
|
|
652
|
-
acceptance: { automated: [], manual: [] },
|
|
653
|
-
matched_patterns: [], matched_knowledge: [],
|
|
654
|
-
is_legacy_code: false, degraded: true,
|
|
655
|
-
contract: { goal: safeGoal, scope: [], constraints: ["task_id 不一致"], verification: [], stop_conditions: ["task_id 不一致"] },
|
|
656
|
-
};
|
|
714
|
+
return buildBlockedResult(`## Contract Error: task_id 不一致\n\nrouteDecision.taskId=${routeDecision.output_artifact.taskId} !== input.task_id=${input.task_id}`, safeGoal, { constraints: ["task_id 不一致"], stopConditions: ["task_id 不一致"] });
|
|
657
715
|
}
|
|
658
716
|
// 路径始终使用 input.task_id
|
|
659
717
|
outputArtifactRecord = createOutputArtifact({
|
|
@@ -688,95 +746,44 @@ export async function expand(input) {
|
|
|
688
746
|
});
|
|
689
747
|
recordCepIntegration("workflow_resolve", cepWfResult);
|
|
690
748
|
if (!workflowContract) {
|
|
691
|
-
return {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
matched_knowledge: [],
|
|
698
|
-
is_legacy_code: false,
|
|
699
|
-
degraded: true,
|
|
700
|
-
workflow_trace: {
|
|
701
|
-
workflow_id: "none",
|
|
702
|
-
route: routeDecision.route,
|
|
703
|
-
execution_shape: routeDecision.execution_shape,
|
|
704
|
-
mutation_allowed: routeDecision.mutation_allowed,
|
|
749
|
+
return buildBlockedResult(`## 阻塞:无工作流契约\n\n任务: ${safeIntent}\n\nroute="${routeDecision.route}" + execution_shape="${routeDecision.execution_shape}" 没有匹配的工作流契约。\n\n请检查意图路由配置。`, safeGoal, {
|
|
750
|
+
constraints: ["无匹配工作流契约"], stopConditions: ["修复意图路由配置"],
|
|
751
|
+
outputArtifactRecord: outputArtifactRecord,
|
|
752
|
+
workflowTrace: {
|
|
753
|
+
workflow_id: "none", route: routeDecision.route,
|
|
754
|
+
execution_shape: routeDecision.execution_shape, mutation_allowed: routeDecision.mutation_allowed,
|
|
705
755
|
required_mechanisms: [],
|
|
706
756
|
governance_findings: [{ severity: "hard_fail", rule: "gc-no-workflow", message: `no workflow contract for ${routeDecision.route}+${routeDecision.execution_shape}` }],
|
|
707
|
-
degraded: true,
|
|
708
|
-
state_transition_target: "none",
|
|
709
|
-
},
|
|
710
|
-
contract: {
|
|
711
|
-
goal: safeGoal,
|
|
712
|
-
scope: [],
|
|
713
|
-
constraints: ["无工作流契约"],
|
|
714
|
-
verification: [],
|
|
715
|
-
stop_conditions: ["无工作流契约"],
|
|
757
|
+
degraded: true, state_transition_target: "none",
|
|
716
758
|
},
|
|
717
|
-
|
|
718
|
-
};
|
|
759
|
+
});
|
|
719
760
|
}
|
|
720
|
-
// mutation_allowed
|
|
721
|
-
if (workflowContract.mutation_allowed !== routeDecision.mutation_allowed) {
|
|
722
|
-
return {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
matched_knowledge: [],
|
|
729
|
-
is_legacy_code: false,
|
|
730
|
-
degraded: true,
|
|
731
|
-
workflow_trace: {
|
|
732
|
-
workflow_id: workflowContract.id,
|
|
733
|
-
route: routeDecision.route,
|
|
734
|
-
execution_shape: routeDecision.execution_shape,
|
|
735
|
-
mutation_allowed: workflowContract.mutation_allowed,
|
|
761
|
+
// mutation_allowed 一致性检查(轻量路径跳过)
|
|
762
|
+
if (!skipWorkflowContractStrict && workflowContract.mutation_allowed !== routeDecision.mutation_allowed) {
|
|
763
|
+
return buildBlockedResult(`## 阻塞:mutation_allowed 不一致\n\n任务: ${safeIntent}\n\n工作流 "${workflowContract.id}" 的 mutation_allowed=${workflowContract.mutation_allowed} 与 route_decision 的 mutation_allowed=${routeDecision.mutation_allowed} 不一致。`, safeGoal, {
|
|
764
|
+
constraints: ["mutation_allowed 不一致"], stopConditions: ["mutation_allowed 不一致"],
|
|
765
|
+
outputArtifactRecord: outputArtifactRecord,
|
|
766
|
+
workflowTrace: {
|
|
767
|
+
workflow_id: workflowContract.id, route: routeDecision.route,
|
|
768
|
+
execution_shape: routeDecision.execution_shape, mutation_allowed: workflowContract.mutation_allowed,
|
|
736
769
|
required_mechanisms: workflowContract.required_mechanisms,
|
|
737
770
|
governance_findings: [{ severity: "hard_fail", rule: "gc-mutation-mismatch", message: `mutation_allowed mismatch: workflow=${workflowContract.mutation_allowed} route=${routeDecision.mutation_allowed}` }],
|
|
738
|
-
degraded: true,
|
|
739
|
-
state_transition_target: "none",
|
|
771
|
+
degraded: true, state_transition_target: "none",
|
|
740
772
|
},
|
|
741
|
-
|
|
742
|
-
goal: safeGoal,
|
|
743
|
-
scope: [],
|
|
744
|
-
constraints: ["mutation_allowed 不一致"],
|
|
745
|
-
verification: [],
|
|
746
|
-
stop_conditions: ["mutation_allowed 不一致"],
|
|
747
|
-
},
|
|
748
|
-
output_artifact_record: outputArtifactRecord,
|
|
749
|
-
};
|
|
773
|
+
});
|
|
750
774
|
}
|
|
751
|
-
// prompt_template
|
|
752
|
-
if (workflowContract.prompt_template !== templateName) {
|
|
753
|
-
return {
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
matched_patterns: [],
|
|
759
|
-
matched_knowledge: [],
|
|
760
|
-
is_legacy_code: false,
|
|
761
|
-
degraded: true,
|
|
762
|
-
workflow_trace: {
|
|
763
|
-
workflow_id: workflowContract.id,
|
|
764
|
-
route: routeDecision.route,
|
|
765
|
-
execution_shape: routeDecision.execution_shape,
|
|
766
|
-
mutation_allowed: workflowContract.mutation_allowed,
|
|
775
|
+
// prompt_template 一致性检查(轻量路径跳过)
|
|
776
|
+
if (!skipWorkflowContractStrict && workflowContract.prompt_template !== templateName) {
|
|
777
|
+
return buildBlockedResult(`## 阻塞:prompt_template 不一致\n\n任务: ${safeIntent}\n\n工作流 "${workflowContract.id}" 要求 prompt_template="${workflowContract.prompt_template}",但 selectPromptTemplate 返回 "${templateName}"。`, safeGoal, {
|
|
778
|
+
constraints: ["prompt_template 不一致"], stopConditions: ["prompt_template 不一致"],
|
|
779
|
+
workflowTrace: {
|
|
780
|
+
workflow_id: workflowContract.id, route: routeDecision.route,
|
|
781
|
+
execution_shape: routeDecision.execution_shape, mutation_allowed: workflowContract.mutation_allowed,
|
|
767
782
|
required_mechanisms: workflowContract.required_mechanisms,
|
|
768
783
|
governance_findings: [{ severity: "hard_fail", rule: "gc-prompt-template-mismatch", message: `prompt_template mismatch: workflow="${workflowContract.prompt_template}" selected="${templateName}"` }],
|
|
769
|
-
degraded: true,
|
|
770
|
-
state_transition_target: "none",
|
|
771
|
-
},
|
|
772
|
-
contract: {
|
|
773
|
-
goal: safeGoal,
|
|
774
|
-
scope: [],
|
|
775
|
-
constraints: ["prompt_template 不一致"],
|
|
776
|
-
verification: [],
|
|
777
|
-
stop_conditions: ["prompt_template 不一致"],
|
|
784
|
+
degraded: true, state_transition_target: "none",
|
|
778
785
|
},
|
|
779
|
-
};
|
|
786
|
+
});
|
|
780
787
|
}
|
|
781
788
|
}
|
|
782
789
|
// 缺少必需输入时返回澄清,不生成执行 prompt(在 workflow resolution 之后)
|
|
@@ -809,40 +816,21 @@ export async function expand(input) {
|
|
|
809
816
|
// ── 输入材料硬阻断──
|
|
810
817
|
if (inputMaterials) {
|
|
811
818
|
const forbiddenMaterials = inputMaterials.filter((m) => m.access_mode === "forbidden");
|
|
812
|
-
if (forbiddenMaterials.length > 0) {
|
|
819
|
+
if (!skipInputMaterialHardBlock && forbiddenMaterials.length > 0) {
|
|
813
820
|
const forbiddenPaths = forbiddenMaterials.map((m) => m.path_or_ref).join(", ");
|
|
814
821
|
debugLog("意图膨胀: 输入材料禁止读取: %s", forbiddenPaths);
|
|
815
|
-
return {
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
is_legacy_code: false,
|
|
823
|
-
degraded: true,
|
|
824
|
-
input_materials: inputMaterials,
|
|
825
|
-
ingestion_evidences: ingestionEvidences,
|
|
826
|
-
prompt_injection_plan: promptInjectionPlan,
|
|
827
|
-
contract: {
|
|
828
|
-
goal: safeGoal,
|
|
829
|
-
scope: [],
|
|
830
|
-
constraints: ["输入材料包含禁止路径"],
|
|
831
|
-
verification: [],
|
|
832
|
-
stop_conditions: [],
|
|
833
|
-
},
|
|
834
|
-
output_artifact_record: outputArtifactRecord,
|
|
835
|
-
workflow_trace: workflowContract ? {
|
|
836
|
-
workflow_id: workflowContract.id,
|
|
837
|
-
route: routeDecision.route,
|
|
838
|
-
execution_shape: routeDecision.execution_shape,
|
|
839
|
-
mutation_allowed: workflowContract.mutation_allowed,
|
|
822
|
+
return buildBlockedResult(`## 阻塞:输入材料禁止读取\n\n任务: ${safeIntent}\n\n以下材料路径触发禁止规则,不得读取:\n${forbiddenMaterials.map((m) => " - " + m.path_or_ref).join("\\n")}\n\n请移除这些材料后重新调用。`, safeGoal, {
|
|
823
|
+
constraints: ["输入材料包含禁止路径"], stopConditions: [],
|
|
824
|
+
inputMaterials: inputMaterials, ingestionEvidences: ingestionEvidences,
|
|
825
|
+
promptInjectionPlan: promptInjectionPlan, outputArtifactRecord: outputArtifactRecord,
|
|
826
|
+
workflowTrace: workflowContract ? {
|
|
827
|
+
workflow_id: workflowContract.id, route: routeDecision.route,
|
|
828
|
+
execution_shape: routeDecision.execution_shape, mutation_allowed: workflowContract.mutation_allowed,
|
|
840
829
|
required_mechanisms: workflowContract.required_mechanisms,
|
|
841
830
|
governance_findings: [{ severity: "hard_fail", rule: "gc-forbidden-material", message: `材料禁止读取: ${forbiddenPaths}` }],
|
|
842
|
-
degraded: true,
|
|
843
|
-
state_transition_target: "none",
|
|
831
|
+
degraded: true, state_transition_target: "none",
|
|
844
832
|
} : undefined,
|
|
845
|
-
};
|
|
833
|
+
});
|
|
846
834
|
}
|
|
847
835
|
const confirmations = input.input_material_confirmations ?? [];
|
|
848
836
|
const requiresConfirmationMaterials = inputMaterials.filter((m) => m.access_mode !== "forbidden"
|
|
@@ -850,37 +838,17 @@ export async function expand(input) {
|
|
|
850
838
|
&& !confirmations.includes(m.path_or_ref));
|
|
851
839
|
if (requiresConfirmationMaterials.length > 0) {
|
|
852
840
|
const confirmPaths = requiresConfirmationMaterials.map((m) => m.path_or_ref);
|
|
853
|
-
return {
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
is_legacy_code: false,
|
|
861
|
-
degraded: true,
|
|
862
|
-
input_materials: inputMaterials,
|
|
863
|
-
ingestion_evidences: ingestionEvidences,
|
|
864
|
-
prompt_injection_plan: promptInjectionPlan,
|
|
865
|
-
contract: {
|
|
866
|
-
goal: safeGoal,
|
|
867
|
-
scope: [],
|
|
868
|
-
constraints: ["输入材料需要确认"],
|
|
869
|
-
verification: [],
|
|
870
|
-
stop_conditions: [],
|
|
871
|
-
},
|
|
872
|
-
output_artifact_record: outputArtifactRecord,
|
|
873
|
-
workflow_trace: workflowContract ? {
|
|
874
|
-
workflow_id: workflowContract.id,
|
|
875
|
-
route: routeDecision.route,
|
|
876
|
-
execution_shape: routeDecision.execution_shape,
|
|
877
|
-
mutation_allowed: workflowContract.mutation_allowed,
|
|
841
|
+
return buildBlockedResult(`## 澄清请求\n\n任务: ${safeIntent}\n\n以下输入材料需要人工确认后才能使用:\n${confirmPaths.map((p) => " - " + p).join("\\n")}\n\n请确认以上材料安全性后,通过 input_material_confirmations 参数重新调用。`, safeGoal, {
|
|
842
|
+
constraints: ["输入材料需要确认"], stopConditions: [],
|
|
843
|
+
inputMaterials: inputMaterials, ingestionEvidences: ingestionEvidences,
|
|
844
|
+
promptInjectionPlan: promptInjectionPlan, outputArtifactRecord: outputArtifactRecord,
|
|
845
|
+
workflowTrace: workflowContract ? {
|
|
846
|
+
workflow_id: workflowContract.id, route: routeDecision.route,
|
|
847
|
+
execution_shape: routeDecision.execution_shape, mutation_allowed: workflowContract.mutation_allowed,
|
|
878
848
|
required_mechanisms: workflowContract.required_mechanisms,
|
|
879
|
-
governance_findings: [],
|
|
880
|
-
degraded: true,
|
|
881
|
-
state_transition_target: "clarifying",
|
|
849
|
+
governance_findings: [], degraded: true, state_transition_target: "clarifying",
|
|
882
850
|
} : undefined,
|
|
883
|
-
};
|
|
851
|
+
});
|
|
884
852
|
}
|
|
885
853
|
}
|
|
886
854
|
// ── 隐私硬阻断门禁 (privacyGate 已在顶部计算) ──
|
|
@@ -890,52 +858,31 @@ export async function expand(input) {
|
|
|
890
858
|
// 硬阻断: 意图或输入材料中包含密钥/凭证
|
|
891
859
|
if (privacyGate.hard_fail) {
|
|
892
860
|
debugLog("意图膨胀: 隐私策略阻断,包含 %d 个禁止来源", privacyGate.blocked_sources.length);
|
|
893
|
-
return
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
degraded: true,
|
|
914
|
-
sensitivity_labels: privacyLabels.length > 0 ? privacyLabels : undefined,
|
|
915
|
-
redaction_records: privacyRedactions.length > 0 ? privacyRedactions : undefined,
|
|
916
|
-
privacy_findings: privacyFindings.length > 0 ? privacyFindings : undefined,
|
|
917
|
-
contract: {
|
|
918
|
-
goal: safeGoal,
|
|
919
|
-
scope: [],
|
|
920
|
-
constraints: ["隐私/敏感信息策略阻断"],
|
|
921
|
-
verification: [],
|
|
922
|
-
stop_conditions: ["隐私/敏感信息策略阻断"],
|
|
923
|
-
},
|
|
924
|
-
input_materials: inputMaterials,
|
|
925
|
-
ingestion_evidences: ingestionEvidences,
|
|
926
|
-
prompt_injection_plan: promptInjectionPlan,
|
|
927
|
-
output_artifact_record: outputArtifactRecord,
|
|
928
|
-
workflow_trace: workflowContract ? {
|
|
929
|
-
workflow_id: workflowContract.id,
|
|
930
|
-
route: routeDecision.route,
|
|
931
|
-
execution_shape: routeDecision.execution_shape,
|
|
932
|
-
mutation_allowed: workflowContract.mutation_allowed,
|
|
861
|
+
return buildBlockedResult([
|
|
862
|
+
"## 阻塞:隐私/敏感信息策略",
|
|
863
|
+
"",
|
|
864
|
+
"任务内容已因隐私策略脱敏",
|
|
865
|
+
"",
|
|
866
|
+
"隐私门禁触发 hard_fail,以下来源包含禁止级别的敏感信息:",
|
|
867
|
+
...privacyGate.blocked_sources.map((s) => " - " + s),
|
|
868
|
+
"",
|
|
869
|
+
"治理发现:",
|
|
870
|
+
...privacyGate.findings.map((f) => ` [${f.severity}] ${f.rule}: ${f.message}`),
|
|
871
|
+
"",
|
|
872
|
+
"请移除敏感信息后重新调用。",
|
|
873
|
+
].join("\n"), safeGoal, {
|
|
874
|
+
constraints: ["隐私/敏感信息策略阻断"], stopConditions: ["隐私/敏感信息策略阻断"],
|
|
875
|
+
sensitivityLabels: privacyLabels, redactionRecords: privacyRedactions, privacyFindings: privacyFindings,
|
|
876
|
+
inputMaterials: inputMaterials, ingestionEvidences: ingestionEvidences,
|
|
877
|
+
promptInjectionPlan: promptInjectionPlan, outputArtifactRecord: outputArtifactRecord,
|
|
878
|
+
workflowTrace: workflowContract ? {
|
|
879
|
+
workflow_id: workflowContract.id, route: routeDecision.route,
|
|
880
|
+
execution_shape: routeDecision.execution_shape, mutation_allowed: workflowContract.mutation_allowed,
|
|
933
881
|
required_mechanisms: workflowContract.required_mechanisms,
|
|
934
882
|
governance_findings: privacyFindings.map((f) => ({ severity: f.severity, rule: f.rule, message: f.message })),
|
|
935
|
-
degraded: true,
|
|
936
|
-
state_transition_target: "none",
|
|
883
|
+
degraded: true, state_transition_target: "none",
|
|
937
884
|
} : undefined,
|
|
938
|
-
};
|
|
885
|
+
});
|
|
939
886
|
}
|
|
940
887
|
// 1. 查询知识库(路由驱动匹配)
|
|
941
888
|
const affectedRepos = getAffectedRepos(classification);
|
|
@@ -971,57 +918,42 @@ export async function expand(input) {
|
|
|
971
918
|
severity: finding.severity,
|
|
972
919
|
message_zh: finding.message_zh,
|
|
973
920
|
})));
|
|
974
|
-
if (projectKnowledgeReport.hard_fail_count > 0) {
|
|
921
|
+
if (!skipProjectKnowledgeHardBlock && projectKnowledgeReport.hard_fail_count > 0) {
|
|
975
922
|
const lines = projectKnowledgeFindings
|
|
976
923
|
.filter((finding) => finding.severity === "hard_fail")
|
|
977
924
|
.map((finding) => `- [${finding.code}] ${finding.rel_path}: ${finding.message_zh}`);
|
|
978
|
-
return
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
acceptance: { automated: [], manual: [] },
|
|
994
|
-
matched_patterns: [],
|
|
995
|
-
matched_knowledge: [],
|
|
996
|
-
is_legacy_code: false,
|
|
997
|
-
degraded: true,
|
|
998
|
-
contract: {
|
|
999
|
-
goal: safeGoal,
|
|
1000
|
-
scope: [],
|
|
1001
|
-
constraints: ["用户项目知识规则不可消费"],
|
|
1002
|
-
verification: ["soloforge audit-project-knowledge"],
|
|
1003
|
-
stop_conditions: ["修复 .soloforge/knowledge hard rule 路由或身份冲突"],
|
|
1004
|
-
},
|
|
1005
|
-
project_knowledge: {
|
|
925
|
+
return buildBlockedResult([
|
|
926
|
+
"## 阻塞:用户项目知识规则不可消费",
|
|
927
|
+
"",
|
|
928
|
+
`任务: ${safeIntent}`,
|
|
929
|
+
"",
|
|
930
|
+
"项目 .soloforge/knowledge 中存在 hard rule 身份、路由或触发条件问题。",
|
|
931
|
+
"这些规则如果继续放行,会让 AI 在真实任务中无法稳定知道该遵守哪些项目规则。",
|
|
932
|
+
"",
|
|
933
|
+
...lines,
|
|
934
|
+
"",
|
|
935
|
+
"请修复以上项目规则后重新调用。",
|
|
936
|
+
].join("\n"), safeGoal, {
|
|
937
|
+
constraints: ["用户项目知识规则不可消费"],
|
|
938
|
+
stopConditions: ["修复 .soloforge/knowledge hard rule 路由或身份冲突"],
|
|
939
|
+
projectKnowledge: {
|
|
1006
940
|
total: projectKnowledgeReport.total,
|
|
1007
941
|
hard_fail_count: projectKnowledgeReport.hard_fail_count,
|
|
1008
942
|
warning_count: projectKnowledgeReport.warning_count,
|
|
1009
943
|
selected: [],
|
|
1010
944
|
findings: projectKnowledgeFindings,
|
|
1011
945
|
},
|
|
1012
|
-
|
|
1013
|
-
workflow_id: workflowContract.id,
|
|
1014
|
-
route: routeDecision?.route ?? "",
|
|
946
|
+
workflowTrace: workflowContract ? {
|
|
947
|
+
workflow_id: workflowContract.id, route: routeDecision?.route ?? "",
|
|
1015
948
|
execution_shape: routeDecision?.execution_shape ?? "",
|
|
1016
949
|
mutation_allowed: workflowContract.mutation_allowed,
|
|
1017
950
|
required_mechanisms: workflowContract.required_mechanisms,
|
|
1018
951
|
governance_findings: projectKnowledgeFindings
|
|
1019
952
|
.filter((finding) => finding.severity === "hard_fail")
|
|
1020
953
|
.map((finding) => ({ severity: "hard_fail", rule: finding.code, message: `${finding.rel_path}: ${finding.message_zh}` })),
|
|
1021
|
-
degraded: true,
|
|
1022
|
-
state_transition_target: "manual_required",
|
|
954
|
+
degraded: true, state_transition_target: "manual_required",
|
|
1023
955
|
} : undefined,
|
|
1024
|
-
};
|
|
956
|
+
});
|
|
1025
957
|
}
|
|
1026
958
|
const projectKnowledgeSelection = lifecycleKnowledgeDecision.knowledge_selection;
|
|
1027
959
|
const selectedProjectKnowledge = projectKnowledgeSelection.selected.map((decision) => decision.asset);
|
|
@@ -1092,38 +1024,20 @@ export async function expand(input) {
|
|
|
1092
1024
|
? injectionReport.missing_required_knowledge.map((m) => m.reason).join("\n")
|
|
1093
1025
|
: "";
|
|
1094
1026
|
const missingSection = missingDesc ? `\n\n缺少的必需知识:\n${missingDesc}` : "";
|
|
1095
|
-
return {
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
is_legacy_code: false,
|
|
1103
|
-
degraded: true,
|
|
1104
|
-
injection_report: injectionReport,
|
|
1105
|
-
input_materials: inputMaterials,
|
|
1106
|
-
ingestion_evidences: ingestionEvidences,
|
|
1107
|
-
prompt_injection_plan: promptInjectionPlan,
|
|
1108
|
-
contract: {
|
|
1109
|
-
goal: safeGoal,
|
|
1110
|
-
scope: [],
|
|
1111
|
-
constraints: ["注入校验失败,等待修正"],
|
|
1112
|
-
verification: [],
|
|
1113
|
-
stop_conditions: ["注入校验失败"],
|
|
1114
|
-
},
|
|
1115
|
-
output_artifact_record: outputArtifactRecord,
|
|
1116
|
-
workflow_trace: workflowContract ? {
|
|
1117
|
-
workflow_id: workflowContract.id,
|
|
1118
|
-
route: routeDecision?.route ?? "",
|
|
1027
|
+
return buildBlockedResult(`## 阻塞:注入校验失败\n\n任务: ${safeIntent}\n\n以下硬性校验未通过:\n${failMessages}${missingSection}\n\n请修正后重新调用。`, safeGoal, {
|
|
1028
|
+
constraints: ["注入校验失败,等待修正"], stopConditions: ["注入校验失败"],
|
|
1029
|
+
injectionReport: injectionReport,
|
|
1030
|
+
inputMaterials: inputMaterials, ingestionEvidences: ingestionEvidences,
|
|
1031
|
+
promptInjectionPlan: promptInjectionPlan, outputArtifactRecord: outputArtifactRecord,
|
|
1032
|
+
workflowTrace: workflowContract ? {
|
|
1033
|
+
workflow_id: workflowContract.id, route: routeDecision?.route ?? "",
|
|
1119
1034
|
execution_shape: routeDecision?.execution_shape ?? "",
|
|
1120
1035
|
mutation_allowed: workflowContract.mutation_allowed,
|
|
1121
1036
|
required_mechanisms: workflowContract.required_mechanisms,
|
|
1122
1037
|
governance_findings: workflowGovernanceFindings,
|
|
1123
|
-
degraded: true,
|
|
1124
|
-
state_transition_target: "none",
|
|
1038
|
+
degraded: true, state_transition_target: "none",
|
|
1125
1039
|
} : undefined,
|
|
1126
|
-
};
|
|
1040
|
+
});
|
|
1127
1041
|
}
|
|
1128
1042
|
// 2. 检测遗留惯例(只对 code_execution 执行)
|
|
1129
1043
|
const legacyConventions = [];
|
|
@@ -1205,8 +1119,8 @@ export async function expand(input) {
|
|
|
1205
1119
|
const uncertaintyTriggers = skipHeavyAnalysis
|
|
1206
1120
|
? []
|
|
1207
1121
|
: buildUncertaintyTriggers(classification, intent);
|
|
1208
|
-
// 机制 1:
|
|
1209
|
-
const breakerResult = checkCircuitBreaker({
|
|
1122
|
+
// 机制 1: 意图熔断器检查(轻量路径跳过)
|
|
1123
|
+
const breakerResult = skipPreImplementationGates ? { tripped: false, confidence: 1.0 } : checkCircuitBreaker({
|
|
1210
1124
|
intent,
|
|
1211
1125
|
classification,
|
|
1212
1126
|
matchedEntries: filteredEntries,
|
|
@@ -1238,10 +1152,10 @@ ${breakerResult.brainstorm.decision_questions.map((q, i) => `${i + 1}. ${q.quest
|
|
|
1238
1152
|
: "请先补齐阻塞输入,或在产物中标记 [Manual Confirm] 后再生成产物。"}
|
|
1239
1153
|
`;
|
|
1240
1154
|
}
|
|
1241
|
-
// problem-16: 技术决策验证 —
|
|
1155
|
+
// problem-16: 技术决策验证 — 仅施工路径 + 高复杂度时校验 human gate
|
|
1242
1156
|
let technologyDecisionEvidence;
|
|
1243
1157
|
let techDecisionRequiresManual = false;
|
|
1244
|
-
if (routeDecision?.execution_shape === "code_execution" && classification.complexity === "high") {
|
|
1158
|
+
if (!skipHeavyContractGates && routeDecision?.execution_shape === "code_execution" && classification.complexity === "high") {
|
|
1245
1159
|
const decisionContract = {
|
|
1246
1160
|
decision_id: `td-${input.task_id ?? "unknown"}`,
|
|
1247
1161
|
decision_scope: "architecture",
|
|
@@ -1280,34 +1194,62 @@ ${breakerResult.brainstorm.decision_questions.map((q, i) => `${i + 1}. ${q.quest
|
|
|
1280
1194
|
});
|
|
1281
1195
|
}
|
|
1282
1196
|
}
|
|
1283
|
-
// problem-41: 脑暴完整性校验 —
|
|
1197
|
+
// problem-41: 脑暴完整性校验 — 仅施工路径校验
|
|
1198
|
+
// 优先使用用户提供的 brainstorm_session,否则从 circuit breaker 自动生成
|
|
1284
1199
|
let brainstormEvidence;
|
|
1285
1200
|
let brainstormRequiresClarification = false;
|
|
1286
|
-
if (circuitBreakerOutput?.brainstorm) {
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1201
|
+
if (!skipHeavyContractGates && (input.brainstorm_session || circuitBreakerOutput?.brainstorm)) {
|
|
1202
|
+
// 优先使用用户提供的 brainstorm_session
|
|
1203
|
+
let session;
|
|
1204
|
+
if (input.brainstorm_session) {
|
|
1205
|
+
session = input.brainstorm_session;
|
|
1206
|
+
}
|
|
1207
|
+
else {
|
|
1208
|
+
const bs = circuitBreakerOutput?.brainstorm;
|
|
1209
|
+
if (!bs) {
|
|
1210
|
+
// 仅在 circuitBreakerOutput?.brainstorm 存在时进入此分支,但 TS 无法推断
|
|
1211
|
+
// 安全跳过:如果 brainstorm 不存在则跳过整个校验
|
|
1212
|
+
return {
|
|
1213
|
+
task_id: "",
|
|
1214
|
+
prompt: `## 脑暴数据缺失\n\n任务: ${safeIntent}\n\n内部脑暴数据不可用,跳过脑暴校验。`,
|
|
1215
|
+
scope: { allowed_paths: [], readonly_paths: [], new_files_allowed: false },
|
|
1216
|
+
acceptance: { automated: [], manual: [] },
|
|
1217
|
+
matched_patterns: [],
|
|
1218
|
+
matched_knowledge: [],
|
|
1219
|
+
is_legacy_code: false,
|
|
1220
|
+
degraded: true,
|
|
1221
|
+
contract: { goal: safeGoal, scope: [], constraints: ["脑暴数据缺失"], verification: [], stop_conditions: [] },
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
session = {
|
|
1225
|
+
session_id: `bs-${input.task_id ?? "unknown"}`,
|
|
1226
|
+
trigger: "ambiguous_goal",
|
|
1227
|
+
problem_statement: input.intent,
|
|
1228
|
+
options: bs.decision_questions.map((q, i) => ({
|
|
1229
|
+
option_id: `opt-${i}`,
|
|
1230
|
+
title: q.question,
|
|
1231
|
+
description: `${q.option_a} vs ${q.option_b}`,
|
|
1232
|
+
pros: [q.option_a],
|
|
1233
|
+
cons: [q.option_b],
|
|
1234
|
+
applicable_when: [],
|
|
1235
|
+
not_applicable_when: [],
|
|
1236
|
+
// 从 decision question 自动填充失败条件
|
|
1237
|
+
failure_conditions: [
|
|
1238
|
+
`选择 ${q.option_a} 失败的条件: ${q.option_a} 的局限性场景`,
|
|
1239
|
+
`选择 ${q.option_b} 失败的条件: ${q.option_b} 的局限性场景`,
|
|
1240
|
+
],
|
|
1241
|
+
verification_method: [],
|
|
1242
|
+
estimated_risk: "medium",
|
|
1243
|
+
reversibility: "partially_reversible",
|
|
1244
|
+
required_human_decisions: [],
|
|
1245
|
+
})),
|
|
1246
|
+
recommended_option_id: "opt-0",
|
|
1247
|
+
rejected_option_ids: [],
|
|
1248
|
+
human_gate_required: true,
|
|
1249
|
+
evidence_refs: [],
|
|
1250
|
+
brainstorm_status: "options_ready",
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1311
1253
|
const brainstormResult = validateBrainstormSession(session);
|
|
1312
1254
|
// 治理结果写入 workflow_trace.governance_findings
|
|
1313
1255
|
if (!brainstormResult.valid) {
|
|
@@ -1635,7 +1577,7 @@ function inferTypeFromSubDir(subDir) {
|
|
|
1635
1577
|
*/
|
|
1636
1578
|
function queryKnowledgeForRoute(knowledgeIndex, intent, scopeFilters, config, routeDecision, limit) {
|
|
1637
1579
|
if (!routeDecision) {
|
|
1638
|
-
// 无 route_decision
|
|
1580
|
+
// 无 route_decision 时回退到旧逻辑(不传 route,不强制路由匹配)
|
|
1639
1581
|
return knowledgeIndex.query({
|
|
1640
1582
|
scope: scopeFilters,
|
|
1641
1583
|
products: [config.product_profile],
|
|
@@ -1643,6 +1585,7 @@ function queryKnowledgeForRoute(knowledgeIndex, intent, scopeFilters, config, ro
|
|
|
1643
1585
|
limit,
|
|
1644
1586
|
});
|
|
1645
1587
|
}
|
|
1588
|
+
const currentRoute = routeDecision.route;
|
|
1646
1589
|
const seen = new Set();
|
|
1647
1590
|
const results = [];
|
|
1648
1591
|
function addEntries(entries) {
|
|
@@ -1660,6 +1603,7 @@ function queryKnowledgeForRoute(knowledgeIndex, intent, scopeFilters, config, ro
|
|
|
1660
1603
|
scope: scopeFilters,
|
|
1661
1604
|
products: [config.product_profile],
|
|
1662
1605
|
type: "pipeline_procedure",
|
|
1606
|
+
route: currentRoute,
|
|
1663
1607
|
keywords: extractKeywords(pipelineName),
|
|
1664
1608
|
limit: 3,
|
|
1665
1609
|
});
|
|
@@ -1680,6 +1624,7 @@ function queryKnowledgeForRoute(knowledgeIndex, intent, scopeFilters, config, ro
|
|
|
1680
1624
|
scope: scopeFilters,
|
|
1681
1625
|
products: [config.product_profile],
|
|
1682
1626
|
type: "acceptance_template",
|
|
1627
|
+
route: currentRoute,
|
|
1683
1628
|
keywords: [],
|
|
1684
1629
|
limit: 100,
|
|
1685
1630
|
});
|
|
@@ -1722,6 +1667,7 @@ function queryKnowledgeForRoute(knowledgeIndex, intent, scopeFilters, config, ro
|
|
|
1722
1667
|
const keywordResults = knowledgeIndex.query({
|
|
1723
1668
|
scope: scopeFilters,
|
|
1724
1669
|
products: [config.product_profile],
|
|
1670
|
+
route: currentRoute,
|
|
1725
1671
|
keywords: extractKeywords(intent),
|
|
1726
1672
|
limit: limit,
|
|
1727
1673
|
});
|