soloforge 1.3.0 → 1.3.2
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/README.md +15 -2
- package/dist/adapters/claude_code/claude_md.d.ts.map +1 -1
- package/dist/adapters/claude_code/claude_md.js +4 -0
- package/dist/adapters/claude_code/claude_md.js.map +1 -1
- package/dist/adapters/claude_code/tools.d.ts +36 -9
- package/dist/adapters/claude_code/tools.d.ts.map +1 -1
- package/dist/adapters/claude_code/tools.js +828 -19
- package/dist/adapters/claude_code/tools.js.map +1 -1
- package/dist/adapters/shared/workflow_template.d.ts +26 -0
- package/dist/adapters/shared/workflow_template.d.ts.map +1 -1
- package/dist/adapters/shared/workflow_template.js +139 -40
- package/dist/adapters/shared/workflow_template.js.map +1 -1
- package/dist/bin/soloforge.d.ts.map +1 -1
- package/dist/bin/soloforge.js +220 -45
- package/dist/bin/soloforge.js.map +1 -1
- package/dist/engine/architecture_decision_workshop.d.ts +58 -0
- package/dist/engine/architecture_decision_workshop.d.ts.map +1 -0
- package/dist/engine/architecture_decision_workshop.js +118 -0
- package/dist/engine/architecture_decision_workshop.js.map +1 -0
- package/dist/engine/asset_manifest.d.ts +7 -1
- package/dist/engine/asset_manifest.d.ts.map +1 -1
- package/dist/engine/asset_manifest.js +36 -15
- package/dist/engine/asset_manifest.js.map +1 -1
- package/dist/engine/consumable_asset_registry.d.ts.map +1 -1
- package/dist/engine/consumable_asset_registry.js +90 -1
- package/dist/engine/consumable_asset_registry.js.map +1 -1
- package/dist/engine/consumption_trace_store.d.ts +8 -8
- package/dist/engine/consumption_trace_store.d.ts.map +1 -1
- package/dist/engine/consumption_trace_store.js +11 -7
- package/dist/engine/consumption_trace_store.js.map +1 -1
- package/dist/engine/decision_workshop.d.ts +160 -0
- package/dist/engine/decision_workshop.d.ts.map +1 -0
- package/dist/engine/decision_workshop.js +279 -0
- package/dist/engine/decision_workshop.js.map +1 -0
- package/dist/engine/design_artifact_pack.d.ts +44 -0
- package/dist/engine/design_artifact_pack.d.ts.map +1 -0
- package/dist/engine/design_artifact_pack.js +167 -0
- package/dist/engine/design_artifact_pack.js.map +1 -0
- package/dist/engine/dual_layer_mechanism_registry.d.ts.map +1 -1
- package/dist/engine/dual_layer_mechanism_registry.js +294 -0
- package/dist/engine/dual_layer_mechanism_registry.js.map +1 -1
- package/dist/engine/evidence_grounding_contract.d.ts +137 -0
- package/dist/engine/evidence_grounding_contract.d.ts.map +1 -0
- package/dist/engine/evidence_grounding_contract.js +410 -0
- package/dist/engine/evidence_grounding_contract.js.map +1 -0
- package/dist/engine/explicit_asset_registry.d.ts +30 -0
- package/dist/engine/explicit_asset_registry.d.ts.map +1 -0
- package/dist/engine/explicit_asset_registry.js +3508 -0
- package/dist/engine/explicit_asset_registry.js.map +1 -0
- package/dist/engine/implementation_roadmap_registry.d.ts +2 -2
- package/dist/engine/implementation_roadmap_registry.d.ts.map +1 -1
- package/dist/engine/implementation_roadmap_registry.js +163 -6
- package/dist/engine/implementation_roadmap_registry.js.map +1 -1
- package/dist/engine/instruction_contract.d.ts +8 -1
- package/dist/engine/instruction_contract.d.ts.map +1 -1
- package/dist/engine/instruction_contract.js +63 -1
- package/dist/engine/instruction_contract.js.map +1 -1
- package/dist/engine/intent_expander.d.ts.map +1 -1
- package/dist/engine/intent_expander.js +60 -2
- package/dist/engine/intent_expander.js.map +1 -1
- package/dist/engine/intent_router.d.ts +1 -1
- package/dist/engine/intent_router.d.ts.map +1 -1
- package/dist/engine/intent_router.js +2 -1
- package/dist/engine/intent_router.js.map +1 -1
- package/dist/engine/knowledge_injection_boundary.d.ts +3 -0
- package/dist/engine/knowledge_injection_boundary.d.ts.map +1 -1
- package/dist/engine/knowledge_injection_boundary.js +48 -5
- package/dist/engine/knowledge_injection_boundary.js.map +1 -1
- package/dist/engine/mechanism_contract_registry.d.ts +1 -1
- package/dist/engine/mechanism_contract_registry.d.ts.map +1 -1
- package/dist/engine/mechanism_contract_registry.js +138 -0
- package/dist/engine/mechanism_contract_registry.js.map +1 -1
- package/dist/engine/observed_consumption.d.ts +54 -0
- package/dist/engine/observed_consumption.d.ts.map +1 -0
- package/dist/engine/observed_consumption.js +377 -0
- package/dist/engine/observed_consumption.js.map +1 -0
- package/dist/engine/platform_context.d.ts.map +1 -1
- package/dist/engine/platform_context.js +6 -2
- package/dist/engine/platform_context.js.map +1 -1
- package/dist/engine/release_gate_scenario_registry.d.ts +16 -1
- package/dist/engine/release_gate_scenario_registry.d.ts.map +1 -1
- package/dist/engine/release_gate_scenario_registry.js +205 -2
- package/dist/engine/release_gate_scenario_registry.js.map +1 -1
- package/dist/engine/release_issue_scenario_registry.d.ts +64 -0
- package/dist/engine/release_issue_scenario_registry.d.ts.map +1 -0
- package/dist/engine/release_issue_scenario_registry.js +1349 -0
- package/dist/engine/release_issue_scenario_registry.js.map +1 -0
- package/dist/engine/release_readiness_gate.d.ts +8 -0
- package/dist/engine/release_readiness_gate.d.ts.map +1 -1
- package/dist/engine/release_readiness_gate.js +1144 -6
- package/dist/engine/release_readiness_gate.js.map +1 -1
- package/dist/engine/release_tool_harness.d.ts +71 -0
- package/dist/engine/release_tool_harness.d.ts.map +1 -0
- package/dist/engine/release_tool_harness.js +161 -0
- package/dist/engine/release_tool_harness.js.map +1 -0
- package/dist/engine/scaffolder.d.ts.map +1 -1
- package/dist/engine/scaffolder.js +144 -7
- package/dist/engine/scaffolder.js.map +1 -1
- package/dist/engine/standard_asset_contract.d.ts +75 -0
- package/dist/engine/standard_asset_contract.d.ts.map +1 -0
- package/dist/engine/standard_asset_contract.js +388 -0
- package/dist/engine/standard_asset_contract.js.map +1 -0
- package/dist/engine/standard_asset_coverage.d.ts +45 -0
- package/dist/engine/standard_asset_coverage.d.ts.map +1 -0
- package/dist/engine/standard_asset_coverage.js +220 -0
- package/dist/engine/standard_asset_coverage.js.map +1 -0
- package/dist/engine/task_context.d.ts +9 -2
- package/dist/engine/task_context.d.ts.map +1 -1
- package/dist/engine/task_context.js +49 -12
- package/dist/engine/task_context.js.map +1 -1
- package/dist/engine/template_asset_contract_registry.d.ts +162 -0
- package/dist/engine/template_asset_contract_registry.d.ts.map +1 -0
- package/dist/engine/template_asset_contract_registry.js +598 -0
- package/dist/engine/template_asset_contract_registry.js.map +1 -0
- package/dist/engine/template_asset_visibility.d.ts +109 -0
- package/dist/engine/template_asset_visibility.d.ts.map +1 -0
- package/dist/engine/template_asset_visibility.js +321 -0
- package/dist/engine/template_asset_visibility.js.map +1 -0
- package/dist/engine/template_init_sync.d.ts +68 -0
- package/dist/engine/template_init_sync.d.ts.map +1 -0
- package/dist/engine/template_init_sync.js +218 -0
- package/dist/engine/template_init_sync.js.map +1 -0
- package/dist/engine/template_manifest_io.d.ts +10 -0
- package/dist/engine/template_manifest_io.d.ts.map +1 -1
- package/dist/engine/template_manifest_io.js +63 -30
- package/dist/engine/template_manifest_io.js.map +1 -1
- package/dist/engine/template_mechanism_auditor.d.ts +3 -1
- package/dist/engine/template_mechanism_auditor.d.ts.map +1 -1
- package/dist/engine/template_mechanism_auditor.js +27 -24
- package/dist/engine/template_mechanism_auditor.js.map +1 -1
- package/dist/engine/tool_invocation_contract_registry.d.ts.map +1 -1
- package/dist/engine/tool_invocation_contract_registry.js +11 -1
- package/dist/engine/tool_invocation_contract_registry.js.map +1 -1
- package/dist/engine/verifier.d.ts.map +1 -1
- package/dist/engine/verifier.js +3 -40
- package/dist/engine/verifier.js.map +1 -1
- package/dist/engine/workflow_contract_registry.d.ts.map +1 -1
- package/dist/engine/workflow_contract_registry.js +4 -3
- package/dist/engine/workflow_contract_registry.js.map +1 -1
- package/dist/knowledge/index_manager.d.ts +20 -0
- package/dist/knowledge/index_manager.d.ts.map +1 -1
- package/dist/knowledge/index_manager.js +234 -3
- package/dist/knowledge/index_manager.js.map +1 -1
- package/dist/types.d.ts +47 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -4
- package/templates/knowledge/acceptance_templates/API/346/216/245/345/217/243/350/247/204/346/240/274/346/226/207/346/241/243/346/250/241/347/211/210.md +74 -0
- package/templates/knowledge/acceptance_templates//346/225/260/346/215/256/345/272/223/350/256/276/350/256/241/346/226/207/346/241/243/346/250/241/347/211/210.md +59 -0
- package/templates/knowledge/acceptance_templates//346/236/266/346/236/204/350/256/276/350/256/241/346/250/241/347/211/210.md +27 -7
- package/templates/knowledge/acceptance_templates//350/256/276/350/256/241/344/270/200/350/207/264/346/200/247/351/252/214/346/224/266/346/212/245/345/221/212/346/250/241/347/211/210.md +47 -0
- package/templates/knowledge/procedures//346/236/266/346/236/204/345/206/263/347/255/226/347/240/224/350/256/250/345/267/245/344/275/234/346/265/201.md +51 -0
- package/templates/knowledge/procedures//346/236/266/346/236/204/350/256/276/350/256/241/345/267/245/344/275/234/346/265/201.md +16 -7
- package/templates/knowledge/procedures//350/256/276/350/256/241/344/272/247/347/211/251/347/224/237/346/210/220/344/270/216/345/244/215/351/252/214/345/267/245/344/275/234/346/265/201.md +45 -0
- package/templates/knowledge/rules//345/267/245/344/275/234/346/265/201/346/250/241/346/235/277/345/214/205/350/247/204/345/210/231.md +10 -0
- package/templates/knowledge/rules//346/211/251/345/261/225/347/224/237/345/221/275/345/221/250/346/234/237/350/247/204/345/210/231.md +10 -0
- package/templates/knowledge/rules//346/226/275/345/267/245/346/214/207/344/273/244/345/245/221/347/272/246/350/247/204/345/210/231.md +33 -4
- package/templates/knowledge/rules//346/236/266/346/236/204/345/206/263/347/255/226/347/240/224/350/256/250/350/247/204/345/210/231.md +49 -0
- package/templates/knowledge/rules//346/240/207/345/207/206/350/265/204/344/272/247/350/246/206/347/233/226/350/247/204/345/210/231.md +29 -0
- package/templates/knowledge/rules//346/250/241/346/235/277/350/265/204/344/272/247/345/217/257/350/247/201/346/200/247/350/247/204/345/210/231.md +27 -0
- package/templates/knowledge/rules//347/224/250/346/210/267/345/217/215/351/246/210/345/245/221/347/272/246/350/247/204/345/210/231.md +62 -1
- package/templates/knowledge/rules//350/256/276/350/256/241/344/272/247/347/211/251/345/214/205/350/247/204/345/210/231.md +55 -0
- package/templates/knowledge/rules//350/257/201/346/215/256/351/251/261/345/212/250/344/270/216/345/217/215/345/271/273/350/247/211/350/247/204/345/210/231.md +75 -0
- package/templates/knowledge/rules//350/267/250/345/271/263/345/217/260/350/267/257/345/276/204/345/256/211/345/205/250/350/247/204/345/210/231.md +10 -0
- package/templates/knowledge/rules//351/200/232/347/224/250/345/206/263/347/255/226/347/240/224/350/256/250/350/247/204/345/210/231.md +30 -0
- package/templates/knowledge/rules//351/252/214/346/224/266/346/250/241/346/235/277/350/276/223/345/207/272/345/245/221/347/272/246/350/247/204/345/210/231.md +50 -0
|
@@ -78,6 +78,11 @@ const lazyTechnologyDecision = createLazy(() => import("../../engine/technology_
|
|
|
78
78
|
const lazyDetailDiscipline = createLazy(() => import("../../engine/detail_discipline.js"));
|
|
79
79
|
const lazyFirstPrinciples = createLazy(() => import("../../engine/first_principles.js"));
|
|
80
80
|
const lazyBrainstormContract = createLazy(() => import("../../engine/brainstorm_contract.js"));
|
|
81
|
+
const lazyArchitectureWorkshop = createLazy(() => import("../../engine/architecture_decision_workshop.js"));
|
|
82
|
+
const lazyDesignArtifactPack = createLazy(() => import("../../engine/design_artifact_pack.js"));
|
|
83
|
+
const lazyStandardAssetContract = createLazy(() => import("../../engine/standard_asset_contract.js"));
|
|
84
|
+
const lazyTemplateVisibility = createLazy(() => import("../../engine/template_asset_visibility.js"));
|
|
85
|
+
const lazyDecisionWorkshop = createLazy(() => import("../../engine/decision_workshop.js"));
|
|
81
86
|
// ── Zod Schema 定义 ──
|
|
82
87
|
const ClassifySchema = {
|
|
83
88
|
intent: z.string().describe("开发者意图描述"),
|
|
@@ -87,6 +92,9 @@ const ExpandSchema = {
|
|
|
87
92
|
task_id: z.string().describe("sf_classify 返回的任务 ID"),
|
|
88
93
|
clarification_answers: z.array(z.string()).optional().describe("对澄清问题的回答"),
|
|
89
94
|
input_material_confirmations: z.array(z.string()).optional().describe("已确认安全的输入材料路径列表"),
|
|
95
|
+
architecture_decision_workshop: z.unknown().optional().describe("架构设计前已讨论并确认的六域决策记录"),
|
|
96
|
+
decision_workshop: z.unknown().optional().describe("通用决策研讨合同(技术选型/数据迁移/安全策略/部署/重构/第三方集成等)"),
|
|
97
|
+
design_artifact_pack: z.unknown().optional().describe("设计产物包路径映射或已复验状态"),
|
|
90
98
|
};
|
|
91
99
|
const VerifySchema = {
|
|
92
100
|
task_id: z.string().describe("任务 ID"),
|
|
@@ -135,6 +143,24 @@ const RecordVerificationExecutionSchema = {
|
|
|
135
143
|
evidence_id: z.string().describe("执行证据 ID"),
|
|
136
144
|
})).describe("真实执行记录列表"),
|
|
137
145
|
};
|
|
146
|
+
const AcceptSchema = {
|
|
147
|
+
task_id: z.string().describe("任务 ID"),
|
|
148
|
+
confirm: z.boolean().describe("用户显式确认验收结果,必须为 true"),
|
|
149
|
+
confirmed_by: z.string().describe("执行确认的用户或审批者标识"),
|
|
150
|
+
confirmation_ref: z.string().describe("可审计的用户确认引用"),
|
|
151
|
+
acceptance_notes: z.string().describe("验收备注或不适用理由"),
|
|
152
|
+
run_mode: z.enum(["manual_review", "not_applicable"]).describe("验收模式"),
|
|
153
|
+
final_access: z.object({
|
|
154
|
+
frontend_urls: z.array(z.string()),
|
|
155
|
+
backend_urls: z.array(z.string()),
|
|
156
|
+
docs_or_swagger_urls: z.array(z.string()),
|
|
157
|
+
start_commands: z.array(z.string()),
|
|
158
|
+
stop_commands: z.array(z.string()),
|
|
159
|
+
running_status: z.string(),
|
|
160
|
+
manual_review_steps_zh: z.array(z.string()),
|
|
161
|
+
known_limits_zh: z.array(z.string()),
|
|
162
|
+
}).optional().describe("manual_review 模式下的真实本地访问证据"),
|
|
163
|
+
};
|
|
138
164
|
const DeliverSchema = {
|
|
139
165
|
task_id: z.string().describe("任务 ID"),
|
|
140
166
|
changed_files: z.array(z.string()).optional().describe("变更文件列表(不传则使用任务记录中的文件)"),
|
|
@@ -218,7 +244,7 @@ export function checkWriteToolPlanGate(params) {
|
|
|
218
244
|
}
|
|
219
245
|
/**
|
|
220
246
|
* 施工指令契约门 — 写操作前检查施工指令完整性。
|
|
221
|
-
*
|
|
247
|
+
* 通过引擎模块函数真实消费。
|
|
222
248
|
* 调用链 1: registerInstructionIssueCandidate(无契约时创建候选 draft)
|
|
223
249
|
* 调用链 2: enforceInstructionBeforeImplementation → checkInstructionCompleteness → validateInstructionContract
|
|
224
250
|
*/
|
|
@@ -245,7 +271,7 @@ export async function checkInstructionContractGate(params) {
|
|
|
245
271
|
if (!instruction)
|
|
246
272
|
return { allowed: true };
|
|
247
273
|
// 消费 enforceInstructionBeforeImplementation(链式消费 checkInstructionCompleteness + validateInstructionContract)
|
|
248
|
-
const result = instrModule.enforceInstructionBeforeImplementation(instruction, params.toolName);
|
|
274
|
+
const result = await instrModule.enforceInstructionBeforeImplementation(instruction, params.toolName);
|
|
249
275
|
// Draft 状态不阻断 — 仅在 confirmed/executing/blocked 状态时强制
|
|
250
276
|
if (instruction.status === "draft") {
|
|
251
277
|
return { allowed: true, findings: result.allowed ? [] : [result.reason_zh] };
|
|
@@ -260,9 +286,25 @@ export async function checkInstructionContractGate(params) {
|
|
|
260
286
|
}
|
|
261
287
|
return { allowed: true };
|
|
262
288
|
}
|
|
289
|
+
/**
|
|
290
|
+
* 设计产物编码门 — 依赖设计包的任务,在真实复验完成前不得写入业务实现。
|
|
291
|
+
* 仅阻断文件/配置/外部交付写入;任务状态、设计文档复验和讨论本身仍可推进。
|
|
292
|
+
*/
|
|
293
|
+
export function checkDesignArtifactWriteGate(params) {
|
|
294
|
+
const implementationWrite = params.sideEffects.some((effect) => ["file_write", "config_write", "external_write", "git_commit", "git_push", "pr_create"].includes(effect));
|
|
295
|
+
if (!implementationWrite || !params.ctx?.design_artifact_pack)
|
|
296
|
+
return { allowed: true };
|
|
297
|
+
if (params.ctx.design_artifact_pack.status === "implementation_ready")
|
|
298
|
+
return { allowed: true };
|
|
299
|
+
return {
|
|
300
|
+
allowed: false,
|
|
301
|
+
diagnostic_code: "SF-DESIGN-PACK-NOT-READY",
|
|
302
|
+
reason: `工具 ${params.toolName} 依赖的设计产物包状态为 ${params.ctx.design_artifact_pack.status},未完成真实复验,不得写入实现或交付`,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
263
305
|
/**
|
|
264
306
|
* 架构设计门 — 架构设计类任务膨胀前执行 reviewArchitectureDesign。
|
|
265
|
-
*
|
|
307
|
+
* Architecture Design Contract enforcement。
|
|
266
308
|
*/
|
|
267
309
|
export async function checkArchitectureDesignGate(params) {
|
|
268
310
|
const route = params.route;
|
|
@@ -287,9 +329,33 @@ export async function checkArchitectureDesignGate(params) {
|
|
|
287
329
|
}
|
|
288
330
|
return { allowed: true };
|
|
289
331
|
}
|
|
332
|
+
/**
|
|
333
|
+
* 架构决策研讨门 — 正式架构设计前六域决策必须闭合。
|
|
334
|
+
* 与是否存在施工指令契约无关,架构设计路由必经此门。
|
|
335
|
+
*/
|
|
336
|
+
export async function checkArchitectureDecisionWorkshopGate(params) {
|
|
337
|
+
const workshopModule = await lazyArchitectureWorkshop();
|
|
338
|
+
if (!workshopModule.requiresArchitectureDecisionWorkshop(params.workflowIntent, params.ctx.intent)) {
|
|
339
|
+
return { allowed: true };
|
|
340
|
+
}
|
|
341
|
+
const existing = params.ctx.architecture_decision_workshop;
|
|
342
|
+
const contract = existing ?? workshopModule.createArchitectureDecisionWorkshop(params.ctx.task_id, params.projectContext ?? "new_system");
|
|
343
|
+
if (params.projectContext === "existing_system" && contract.project_context !== "existing_system") {
|
|
344
|
+
contract.project_context = "existing_system";
|
|
345
|
+
}
|
|
346
|
+
const evaluatedContract = workshopModule.applyArchitectureWorkshopGate(contract) ?? contract;
|
|
347
|
+
const gate = workshopModule.evaluateArchitectureDecisionWorkshop(evaluatedContract);
|
|
348
|
+
params.ctx.architecture_decision_workshop = evaluatedContract;
|
|
349
|
+
return {
|
|
350
|
+
allowed: gate.allowed,
|
|
351
|
+
findings: gate.blocking_findings,
|
|
352
|
+
next_domain: gate.next_domain,
|
|
353
|
+
contract: evaluatedContract,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
290
356
|
/**
|
|
291
357
|
* 现有系统分析门 — 现有项目编码前必须先做分析。
|
|
292
|
-
*
|
|
358
|
+
* Existing System Analysis Contract enforcement。
|
|
293
359
|
*/
|
|
294
360
|
export async function checkExistingSystemAnalysisGate(params) {
|
|
295
361
|
const archModule = await lazyExistingSystemAnalysis();
|
|
@@ -306,7 +372,7 @@ export async function checkExistingSystemAnalysisGate(params) {
|
|
|
306
372
|
}
|
|
307
373
|
/**
|
|
308
374
|
* 编码就绪门 — 编码前必须有测试计划 + 验收标准。
|
|
309
|
-
*
|
|
375
|
+
* Coding Readiness / Test-First enforcement。
|
|
310
376
|
*/
|
|
311
377
|
export async function checkCodingReadinessGate(params) {
|
|
312
378
|
if (!params.ctx)
|
|
@@ -331,7 +397,7 @@ export async function checkCodingReadinessGate(params) {
|
|
|
331
397
|
}
|
|
332
398
|
/**
|
|
333
399
|
* 本地验收门 — 前端/全栈交付前必须有本地访问证据。
|
|
334
|
-
*
|
|
400
|
+
* Local Docker / Browser Acceptance enforcement。
|
|
335
401
|
*/
|
|
336
402
|
export async function checkLocalAcceptanceGate(params) {
|
|
337
403
|
const acceptanceModule = await lazyLocalAcceptance();
|
|
@@ -353,6 +419,21 @@ export async function checkLocalAcceptanceGate(params) {
|
|
|
353
419
|
required_but_missing: ["local_acceptance_evidence", "final_access_url"],
|
|
354
420
|
};
|
|
355
421
|
}
|
|
422
|
+
if (evidence.run_mode === "not_applicable") {
|
|
423
|
+
return {
|
|
424
|
+
allowed: false,
|
|
425
|
+
reason_zh: "该项目需要本地验收,不得以 not_applicable 代替真实访问证据",
|
|
426
|
+
required_but_missing: ["manual_review", "final_access_url"],
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
const finalAccessResult = acceptanceModule.validateFinalAccess(evidence.final_access, requirement.run_mode);
|
|
430
|
+
if (!finalAccessResult.passed) {
|
|
431
|
+
return {
|
|
432
|
+
allowed: false,
|
|
433
|
+
reason_zh: `本地验收证据不完整: ${finalAccessResult.blocking_reasons.join("; ")}`,
|
|
434
|
+
required_but_missing: ["validated_final_access"],
|
|
435
|
+
};
|
|
436
|
+
}
|
|
356
437
|
return { allowed: true };
|
|
357
438
|
}
|
|
358
439
|
// ── S4 触发判定函数 ──
|
|
@@ -441,7 +522,7 @@ export function requiresBrainstorm(ctx, route) {
|
|
|
441
522
|
}
|
|
442
523
|
/**
|
|
443
524
|
* 技术选型决策门 — 高影响技术决策需用户确认。
|
|
444
|
-
*
|
|
525
|
+
* Decision Sovereignty enforcement。
|
|
445
526
|
* 不依赖 hasInstructionContract — 触发由 requiresDecisionSovereignty 判定。
|
|
446
527
|
*/
|
|
447
528
|
export async function checkDecisionSovereigntyGate(params) {
|
|
@@ -481,7 +562,7 @@ export async function checkDecisionSovereigntyGate(params) {
|
|
|
481
562
|
}
|
|
482
563
|
/**
|
|
483
564
|
* 细节纪律门 — 复杂任务缺关键细节维度时阻断。
|
|
484
|
-
*
|
|
565
|
+
* Detail Discipline enforcement。
|
|
485
566
|
* 不依赖 hasInstructionContract — 触发由 requiresDetailDiscipline 判定。
|
|
486
567
|
*/
|
|
487
568
|
export async function checkDetailDisciplineGate(params) {
|
|
@@ -506,7 +587,7 @@ export async function checkDetailDisciplineGate(params) {
|
|
|
506
587
|
}
|
|
507
588
|
/**
|
|
508
589
|
* 第一性原理门 — 高影响任务需目标/约束/本质问题/权衡。
|
|
509
|
-
*
|
|
590
|
+
* First Principles enforcement。
|
|
510
591
|
* 不依赖 hasInstructionContract — 触发由 requiresFirstPrinciples 判定。
|
|
511
592
|
*/
|
|
512
593
|
export async function checkFirstPrinciplesGate(params) {
|
|
@@ -529,7 +610,7 @@ export async function checkFirstPrinciplesGate(params) {
|
|
|
529
610
|
}
|
|
530
611
|
/**
|
|
531
612
|
* 脑暴/方案探索门 — 不确定项需多方案+推荐理由+用户确认。
|
|
532
|
-
*
|
|
613
|
+
* Brainstorm Contract enforcement。
|
|
533
614
|
* 不依赖 hasInstructionContract — 触发由 requiresBrainstorm 判定。
|
|
534
615
|
*/
|
|
535
616
|
export async function checkBrainstormGate(params) {
|
|
@@ -740,12 +821,14 @@ export async function registerTools(server, deps) {
|
|
|
740
821
|
}
|
|
741
822
|
/** State precheck: validate task status before contract guard */
|
|
742
823
|
const STATE_PRECHECKS = {
|
|
824
|
+
sf_accept: ["executing", "verifying", "retrying"],
|
|
743
825
|
sf_verify: ["executing", "retrying"],
|
|
744
826
|
sf_record_verification_execution: ["verifying", "executing"],
|
|
745
827
|
sf_learn: ["verifying", "executing"],
|
|
746
828
|
sf_expand: ["classifying", "expanding", "clarifying"],
|
|
747
829
|
};
|
|
748
830
|
const STATE_ERROR_LABELS = {
|
|
831
|
+
sf_accept: "不可验收",
|
|
749
832
|
sf_verify: "不可验证",
|
|
750
833
|
sf_record_verification_execution: "不可录入验证结果",
|
|
751
834
|
sf_learn: "不可学习",
|
|
@@ -956,6 +1039,35 @@ export async function registerTools(server, deps) {
|
|
|
956
1039
|
};
|
|
957
1040
|
}
|
|
958
1041
|
}
|
|
1042
|
+
// 问题六十二: MCP 写入路径同样必须消费设计产物包状态,不能绕开 CLI hook。
|
|
1043
|
+
if (hasWriteEffect && taskId) {
|
|
1044
|
+
const designWriteGate = checkDesignArtifactWriteGate({ ctx, toolName: name, sideEffects: effectiveSideEffects });
|
|
1045
|
+
if (!designWriteGate.allowed) {
|
|
1046
|
+
const designViolation = {
|
|
1047
|
+
invocation_id: invocationId, tool_name: name,
|
|
1048
|
+
violation_type: "guard_blocked", severity: "hard_fail",
|
|
1049
|
+
reason: designWriteGate.reason ?? "设计产物包未达到实现就绪状态",
|
|
1050
|
+
recovery: "仅可继续补充设计资产并执行 sf_verify 真实复验;通过前不得写入业务实现",
|
|
1051
|
+
};
|
|
1052
|
+
const designTrace = createToolTrace({
|
|
1053
|
+
tool_name: name, invocation_id: invocationId, task_id: taskId,
|
|
1054
|
+
actual_side_effects: effectiveSideEffects,
|
|
1055
|
+
next_allowed_tools: contract.default_next_tools,
|
|
1056
|
+
forbidden_tools: contract.forbidden_next_tools,
|
|
1057
|
+
authorization, bypass,
|
|
1058
|
+
});
|
|
1059
|
+
await taskContext.setToolTrace(taskId, designTrace, [designViolation]);
|
|
1060
|
+
return {
|
|
1061
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
1062
|
+
error: designViolation.reason,
|
|
1063
|
+
violation: designViolation,
|
|
1064
|
+
diagnostic_code: designWriteGate.diagnostic_code,
|
|
1065
|
+
recovery: designViolation.recovery,
|
|
1066
|
+
}) }],
|
|
1067
|
+
isError: true,
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
959
1071
|
// 合同验证
|
|
960
1072
|
const lastTrace = ctx?.last_tool_trace;
|
|
961
1073
|
// 为动态工具构建有效的合同覆盖(如 sf_status cancel)
|
|
@@ -1017,13 +1129,19 @@ export async function registerTools(server, deps) {
|
|
|
1017
1129
|
// 从 { result } 模式中提取数据
|
|
1018
1130
|
const data = raw?.result !== undefined ? raw.result : raw;
|
|
1019
1131
|
const hasError = !!(data && typeof data === "object" && "error" in data);
|
|
1020
|
-
|
|
1132
|
+
const recoveryNextTools = hasError && Array.isArray(data.recovery_next_tools)
|
|
1133
|
+
? data.recovery_next_tools
|
|
1134
|
+
: contract.default_next_tools;
|
|
1135
|
+
const recoveryForbiddenTools = hasError && Array.isArray(data.recovery_forbidden_tools)
|
|
1136
|
+
? data.recovery_forbidden_tools
|
|
1137
|
+
: contract.forbidden_next_tools;
|
|
1138
|
+
// 构建 trace;失败处理器可显式开放修复重验路径
|
|
1021
1139
|
const trace = createToolTrace({
|
|
1022
1140
|
tool_name: name, invocation_id: invocationId, task_id: taskId,
|
|
1023
1141
|
workflow_id: ctx?.expansion?.workflow_trace?.workflow_id,
|
|
1024
1142
|
actual_side_effects: effectiveSideEffects,
|
|
1025
|
-
next_allowed_tools:
|
|
1026
|
-
forbidden_tools:
|
|
1143
|
+
next_allowed_tools: recoveryNextTools,
|
|
1144
|
+
forbidden_tools: recoveryForbiddenTools,
|
|
1027
1145
|
authorization, bypass,
|
|
1028
1146
|
});
|
|
1029
1147
|
// 将 trace 写入 TaskContext
|
|
@@ -1034,8 +1152,8 @@ export async function registerTools(server, deps) {
|
|
|
1034
1152
|
const response = {
|
|
1035
1153
|
...data,
|
|
1036
1154
|
tool_trace: trace,
|
|
1037
|
-
next_allowed_tools:
|
|
1038
|
-
forbidden_tools:
|
|
1155
|
+
next_allowed_tools: recoveryNextTools,
|
|
1156
|
+
forbidden_tools: recoveryForbiddenTools,
|
|
1039
1157
|
};
|
|
1040
1158
|
// 基于状态的回退: 在响应中暴露降级 workflow
|
|
1041
1159
|
if (authorization.reason === "task in valid state for tool") {
|
|
@@ -1168,9 +1286,22 @@ export async function registerTools(server, deps) {
|
|
|
1168
1286
|
if (!ctx || !ctx.classification) {
|
|
1169
1287
|
return { result: { error: "任务不存在或尚未分类,请先调用 sf_classify" } };
|
|
1170
1288
|
}
|
|
1289
|
+
if (args.architecture_decision_workshop) {
|
|
1290
|
+
ctx.architecture_decision_workshop = args.architecture_decision_workshop;
|
|
1291
|
+
}
|
|
1292
|
+
if (args.decision_workshop) {
|
|
1293
|
+
ctx.decision_workshop = args.decision_workshop;
|
|
1294
|
+
}
|
|
1295
|
+
if (args.design_artifact_pack) {
|
|
1296
|
+
ctx.design_artifact_pack = args.design_artifact_pack;
|
|
1297
|
+
}
|
|
1298
|
+
if (args.architecture_decision_workshop || args.decision_workshop || args.design_artifact_pack) {
|
|
1299
|
+
await taskContext.save(ctx);
|
|
1300
|
+
}
|
|
1171
1301
|
// 状态守卫:classifying/expanding/clarifying → expanding
|
|
1172
1302
|
if (ctx.status === "classifying" || ctx.status === "clarifying") {
|
|
1173
1303
|
await taskContext.updateStatus(args.task_id, "expanding");
|
|
1304
|
+
ctx.status = "expanding";
|
|
1174
1305
|
}
|
|
1175
1306
|
else if (ctx.status !== "expanding") {
|
|
1176
1307
|
return {
|
|
@@ -1247,7 +1378,202 @@ export async function registerTools(server, deps) {
|
|
|
1247
1378
|
gateway.endTask();
|
|
1248
1379
|
}
|
|
1249
1380
|
expansion.task_id = args.task_id;
|
|
1250
|
-
|
|
1381
|
+
const projectRoot = fss.realpathSync(projectPath);
|
|
1382
|
+
const referencedMaterialPaths = new Set((expansion.input_materials ?? [])
|
|
1383
|
+
.map((material) => material.path_or_ref)
|
|
1384
|
+
.filter((materialPath) => typeof materialPath === "string" && materialPath.length > 0)
|
|
1385
|
+
.map((materialPath) => path.resolve(projectRoot, materialPath)));
|
|
1386
|
+
const confirmedProjectSourcePaths = (args.input_material_confirmations ?? [])
|
|
1387
|
+
.map((materialPath) => path.resolve(projectRoot, materialPath))
|
|
1388
|
+
.filter((absolutePath) => absolutePath === projectRoot || absolutePath.startsWith(`${projectRoot}${path.sep}`))
|
|
1389
|
+
.filter((absolutePath) => referencedMaterialPaths.has(absolutePath))
|
|
1390
|
+
.filter((absolutePath) => {
|
|
1391
|
+
try {
|
|
1392
|
+
return fss.statSync(absolutePath).isFile()
|
|
1393
|
+
&& fss.realpathSync(absolutePath).startsWith(`${projectRoot}${path.sep}`);
|
|
1394
|
+
}
|
|
1395
|
+
catch {
|
|
1396
|
+
return false;
|
|
1397
|
+
}
|
|
1398
|
+
});
|
|
1399
|
+
const registerConfirmedProjectSources = (registry) => {
|
|
1400
|
+
for (const absolutePath of confirmedProjectSourcePaths) {
|
|
1401
|
+
const sourceRef = path.relative(projectRoot, absolutePath);
|
|
1402
|
+
registry.register({
|
|
1403
|
+
source_type: "project_file",
|
|
1404
|
+
evidence_role: "project_source_file",
|
|
1405
|
+
authority: "authoritative",
|
|
1406
|
+
freshness: "current",
|
|
1407
|
+
permission: "allowed",
|
|
1408
|
+
scope: "confirmed_input_material",
|
|
1409
|
+
description: `已确认项目输入材料: ${sourceRef}`,
|
|
1410
|
+
source_ref: sourceRef,
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
const workflowIntent = ctx.route_decision?.workflow_intent ?? ctx.classification.route_decision?.workflow_intent;
|
|
1415
|
+
// 问题六十: 高风险项目事实声明先过证据门,避免后续架构研讨门遮蔽无证据问题。
|
|
1416
|
+
{
|
|
1417
|
+
const evRoute = ctx.route_decision?.route ?? ctx.classification?.route_decision?.route;
|
|
1418
|
+
const evWorkflowIntent = ctx.route_decision?.workflow_intent ?? ctx.classification?.route_decision?.workflow_intent;
|
|
1419
|
+
const evRisk = (await import("../../engine/evidence_grounding_contract.js")).assessTaskRisk(ctx.classification?.task_type, evRoute, ctx.intent);
|
|
1420
|
+
const isArchitectureContext = evWorkflowIntent === "architecture_design"
|
|
1421
|
+
|| evWorkflowIntent === "existing_system_gap_analysis"
|
|
1422
|
+
|| evRoute === "artifact_generation"
|
|
1423
|
+
|| /架构|architecture|系统设计|技术方案|现有系统|差距分析|gap.?analysis/i.test(ctx.intent ?? "");
|
|
1424
|
+
if (isArchitectureContext && (evRisk === "high" || evRisk === "critical")) {
|
|
1425
|
+
const { createEvidenceGroundingSystem } = await import("../../engine/evidence_grounding_contract.js");
|
|
1426
|
+
const evg = createEvidenceGroundingSystem();
|
|
1427
|
+
evg.registry.register({
|
|
1428
|
+
source_type: "task_context",
|
|
1429
|
+
evidence_role: "classification",
|
|
1430
|
+
authority: "authoritative",
|
|
1431
|
+
freshness: "current",
|
|
1432
|
+
permission: "allowed",
|
|
1433
|
+
scope: "classification",
|
|
1434
|
+
description: "任务分类结果",
|
|
1435
|
+
source_ref: `task:${args.task_id}`,
|
|
1436
|
+
});
|
|
1437
|
+
if (knowledgeIndex) {
|
|
1438
|
+
const { project } = knowledgeIndex.getAllEntries();
|
|
1439
|
+
for (const entry of project) {
|
|
1440
|
+
if (entry.status !== "active")
|
|
1441
|
+
continue;
|
|
1442
|
+
evg.registry.register({
|
|
1443
|
+
source_type: "knowledge_asset",
|
|
1444
|
+
evidence_role: "template_guidance",
|
|
1445
|
+
authority: "trusted",
|
|
1446
|
+
freshness: "current",
|
|
1447
|
+
permission: "allowed",
|
|
1448
|
+
scope: entry.scope?.join(",") ?? "knowledge",
|
|
1449
|
+
description: entry.name,
|
|
1450
|
+
source_ref: entry.file_path,
|
|
1451
|
+
});
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
const tdc = ctx?.technology_decision_contract;
|
|
1455
|
+
if (tdc?.human_gate_evidence) {
|
|
1456
|
+
evg.registry.register({
|
|
1457
|
+
source_type: "user_confirmation",
|
|
1458
|
+
evidence_role: "user_confirmation",
|
|
1459
|
+
authority: "authoritative",
|
|
1460
|
+
freshness: "current",
|
|
1461
|
+
permission: "allowed",
|
|
1462
|
+
scope: "technology_decision",
|
|
1463
|
+
description: `技术决策确认: ${tdc.decision_scope ?? "general"}`,
|
|
1464
|
+
source_ref: `decision:${tdc.decision_id ?? args.task_id}`,
|
|
1465
|
+
});
|
|
1466
|
+
}
|
|
1467
|
+
registerConfirmedProjectSources(evg.registry);
|
|
1468
|
+
const evClaims = [
|
|
1469
|
+
{
|
|
1470
|
+
id: "claim-expand-0",
|
|
1471
|
+
category: "user_confirmation",
|
|
1472
|
+
claim_text: "任务路由和执行范围已确认",
|
|
1473
|
+
evidence_ids: evg.registry.query({ source_type: "task_context" }).map((e) => e.id),
|
|
1474
|
+
is_uncertain: false,
|
|
1475
|
+
risk_level: evRisk,
|
|
1476
|
+
},
|
|
1477
|
+
{
|
|
1478
|
+
id: "claim-expand-1",
|
|
1479
|
+
category: "architecture",
|
|
1480
|
+
claim_text: "技术方案基于现有系统分析",
|
|
1481
|
+
evidence_ids: evg.registry.query({}).filter((e) => e.evidence_role && e.evidence_role !== "template_guidance" && e.evidence_role !== "classification").map((e) => e.id),
|
|
1482
|
+
is_uncertain: false,
|
|
1483
|
+
risk_level: evRisk,
|
|
1484
|
+
},
|
|
1485
|
+
];
|
|
1486
|
+
const evMatrix = evg.builder.buildContext(evClaims, {
|
|
1487
|
+
target_claims: evClaims.map((c) => c.claim_text),
|
|
1488
|
+
source_types: [],
|
|
1489
|
+
keywords: [],
|
|
1490
|
+
max_results: 10,
|
|
1491
|
+
});
|
|
1492
|
+
evMatrix.task_id = args.task_id;
|
|
1493
|
+
const evGate = evg.gate.evaluate(evMatrix, evRisk);
|
|
1494
|
+
await taskContext.setEvidenceGroundingResult(args.task_id, {
|
|
1495
|
+
evidence_matrix: evMatrix,
|
|
1496
|
+
evidence_gate_result: evGate,
|
|
1497
|
+
unsupported_claims: evGate.unsupported_claims,
|
|
1498
|
+
conflict_resolutions: evMatrix.conflicts,
|
|
1499
|
+
});
|
|
1500
|
+
if (!evGate.allowed) {
|
|
1501
|
+
return {
|
|
1502
|
+
result: {
|
|
1503
|
+
error: `证据驱动门禁阻断: ${evGate.reason_zh}`,
|
|
1504
|
+
diagnostic_code: evGate.diagnostic_code,
|
|
1505
|
+
reason_zh: evGate.reason_zh,
|
|
1506
|
+
unsupported_claims: evGate.unsupported_claims,
|
|
1507
|
+
missing_evidence: evGate.missing_evidence,
|
|
1508
|
+
status: "blocked",
|
|
1509
|
+
recovery: "请提供项目文件、命令输出或其他权威证据支撑关键声明后重新 sf_expand",
|
|
1510
|
+
},
|
|
1511
|
+
};
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
// 问题六十一: 架构设计前的六域研讨门独立执行,不得被施工指令契约有无绕过。
|
|
1516
|
+
const existingSourceRoot = ["src", "backend", "frontend", "apps", "services"].some((candidate) => fss.existsSync(path.join(projectPath, candidate)));
|
|
1517
|
+
const existingManifest = ["package.json", "pom.xml", "build.gradle", "settings.gradle"].some((candidate) => fss.existsSync(path.join(projectPath, candidate)));
|
|
1518
|
+
const detectedArchitectureContext = existingSourceRoot && existingManifest
|
|
1519
|
+
? "existing_system"
|
|
1520
|
+
: (!existingSourceRoot && !existingManifest ? "empty_project" : "new_system");
|
|
1521
|
+
const workshopGate = await checkArchitectureDecisionWorkshopGate({
|
|
1522
|
+
ctx,
|
|
1523
|
+
workflowIntent,
|
|
1524
|
+
projectContext: detectedArchitectureContext,
|
|
1525
|
+
});
|
|
1526
|
+
await taskContext.save(ctx);
|
|
1527
|
+
if (!workshopGate.allowed) {
|
|
1528
|
+
return {
|
|
1529
|
+
result: {
|
|
1530
|
+
error: "架构设计前必须先完成六类架构决策研讨与用户确认",
|
|
1531
|
+
status: "awaiting_confirmation",
|
|
1532
|
+
architecture_decision_workshop: workshopGate.contract,
|
|
1533
|
+
blocking_findings: workshopGate.findings,
|
|
1534
|
+
next_domain: workshopGate.next_domain,
|
|
1535
|
+
recovery: "请从当前待讨论域开始,提供候选方案、推荐理由、风险和用户确认后重新调用 sf_expand",
|
|
1536
|
+
},
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
// 六域决策闭合后创建设计产物生命周期;正式设计与后续实现必须以其复验结果为准。
|
|
1540
|
+
if (workflowIntent === "architecture_design" && !ctx.design_artifact_pack) {
|
|
1541
|
+
const designModule = await lazyDesignArtifactPack();
|
|
1542
|
+
ctx.design_artifact_pack = designModule.createDesignArtifactPack(args.task_id);
|
|
1543
|
+
ctx.design_artifact_pack.status = "awaiting_decisions";
|
|
1544
|
+
ctx.design_artifact_pack.decision_workshop_ref = `task:${args.task_id}:architecture_decision_workshop`;
|
|
1545
|
+
ctx.design_artifact_pack.user_confirmation_ref = ctx.architecture_decision_workshop?.document_output_confirmation_ref;
|
|
1546
|
+
await taskContext.save(ctx);
|
|
1547
|
+
}
|
|
1548
|
+
// 问题六十一(通用): 可组合决策包门禁
|
|
1549
|
+
const dwModule = await lazyDecisionWorkshop();
|
|
1550
|
+
const packMatch = dwModule.matchDecisionPacks({
|
|
1551
|
+
workflow_intent: workflowIntent,
|
|
1552
|
+
intent: ctx.intent,
|
|
1553
|
+
task_type: ctx.classification?.task_type,
|
|
1554
|
+
});
|
|
1555
|
+
// 过滤掉架构(架构由上面的专用子包处理)
|
|
1556
|
+
const nonArchPacks = packMatch.packs.filter((p) => p !== "architecture");
|
|
1557
|
+
if (nonArchPacks.length > 0) {
|
|
1558
|
+
const dwContract = ctx.decision_workshop ?? dwModule.createDecisionWorkshop(args.task_id, nonArchPacks, detectedArchitectureContext, packMatch.reasons.join(";"));
|
|
1559
|
+
const dwGate = dwModule.evaluateDecisionWorkshop(dwContract);
|
|
1560
|
+
ctx.decision_workshop = dwModule.applyDecisionWorkshopGate(dwContract);
|
|
1561
|
+
await taskContext.save(ctx);
|
|
1562
|
+
if (!dwGate.allowed) {
|
|
1563
|
+
return {
|
|
1564
|
+
result: {
|
|
1565
|
+
error: `${packMatch.reasons.join(";")},必须先完成决策研讨与用户确认`,
|
|
1566
|
+
status: "awaiting_confirmation",
|
|
1567
|
+
decision_workshop: ctx.decision_workshop,
|
|
1568
|
+
blocking_findings: dwGate.blocking_findings,
|
|
1569
|
+
next_domain: dwGate.next_domain,
|
|
1570
|
+
activated_packs: nonArchPacks,
|
|
1571
|
+
recovery: "请从当前待讨论域开始,提供候选方案、推荐理由、风险和用户确认后重新调用 sf_expand",
|
|
1572
|
+
},
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
// 问题四十九/五十: 已有架构合同或现有系统证据的进一步审查。
|
|
1251
1577
|
const expansionRoute = expansion.workflow_trace
|
|
1252
1578
|
? expansion.workflow_trace?.route
|
|
1253
1579
|
: undefined;
|
|
@@ -1361,7 +1687,125 @@ export async function registerTools(server, deps) {
|
|
|
1361
1687
|
advisories.h1_advisory = h1Warning;
|
|
1362
1688
|
if (h4LockWarning)
|
|
1363
1689
|
advisories.h4_advisory = h4LockWarning;
|
|
1364
|
-
//
|
|
1690
|
+
// 问题六十:证据驱动门禁 — 高风险任务必须阻断无证据声明
|
|
1691
|
+
const _evRoute = ctx.route_decision?.route ?? ctx.classification?.route_decision?.route;
|
|
1692
|
+
const _evRisk = (await import("../../engine/evidence_grounding_contract.js")).assessTaskRisk(ctx.classification?.task_type, _evRoute, ctx.intent);
|
|
1693
|
+
if (_evRisk === "high" || _evRisk === "critical") {
|
|
1694
|
+
const { createEvidenceGroundingSystem } = await import("../../engine/evidence_grounding_contract.js");
|
|
1695
|
+
const _evg = createEvidenceGroundingSystem();
|
|
1696
|
+
if (ctx.classification) {
|
|
1697
|
+
_evg.registry.register({
|
|
1698
|
+
source_type: "task_context",
|
|
1699
|
+
evidence_role: "classification",
|
|
1700
|
+
authority: "authoritative",
|
|
1701
|
+
freshness: "current",
|
|
1702
|
+
permission: "allowed",
|
|
1703
|
+
scope: "classification",
|
|
1704
|
+
description: "任务分类结果",
|
|
1705
|
+
source_ref: `task:${args.task_id}`,
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1708
|
+
// 注册知识索引中的项目知识作为证据(仅项目级,不含全局通用规则)
|
|
1709
|
+
// 所有知识索引条目都是 template_guidance 角色,不得支撑项目事实声明
|
|
1710
|
+
if (knowledgeIndex) {
|
|
1711
|
+
const { project } = knowledgeIndex.getAllEntries();
|
|
1712
|
+
for (const entry of project) {
|
|
1713
|
+
if (entry.status !== "active")
|
|
1714
|
+
continue;
|
|
1715
|
+
_evg.registry.register({
|
|
1716
|
+
source_type: "knowledge_asset",
|
|
1717
|
+
evidence_role: "template_guidance",
|
|
1718
|
+
authority: "trusted",
|
|
1719
|
+
freshness: "current",
|
|
1720
|
+
permission: "allowed",
|
|
1721
|
+
scope: entry.scope?.join(",") ?? "knowledge",
|
|
1722
|
+
description: entry.name,
|
|
1723
|
+
source_ref: entry.file_path,
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
// 技术决策契约含 human_gate_evidence → 注册为 user_confirmation(真实项目证据)
|
|
1728
|
+
const _tdc = ctx?.technology_decision_contract;
|
|
1729
|
+
if (_tdc?.human_gate_evidence) {
|
|
1730
|
+
_evg.registry.register({
|
|
1731
|
+
source_type: "user_confirmation",
|
|
1732
|
+
evidence_role: "user_confirmation",
|
|
1733
|
+
authority: "authoritative",
|
|
1734
|
+
freshness: "current",
|
|
1735
|
+
permission: "allowed",
|
|
1736
|
+
scope: "technology_decision",
|
|
1737
|
+
description: `技术决策确认: ${_tdc.decision_scope ?? "general"}`,
|
|
1738
|
+
source_ref: `decision:${_tdc.decision_id ?? args.task_id}`,
|
|
1739
|
+
});
|
|
1740
|
+
}
|
|
1741
|
+
registerConfirmedProjectSources(_evg.registry);
|
|
1742
|
+
const _evClaims = [
|
|
1743
|
+
{
|
|
1744
|
+
id: "claim-expand-0",
|
|
1745
|
+
category: "user_confirmation",
|
|
1746
|
+
claim_text: "任务路由和执行范围已确认",
|
|
1747
|
+
evidence_ids: _evg.registry.query({ source_type: "task_context" }).map((e) => e.id),
|
|
1748
|
+
is_uncertain: false,
|
|
1749
|
+
risk_level: _evRisk,
|
|
1750
|
+
},
|
|
1751
|
+
];
|
|
1752
|
+
// 只在架构设计/现有系统分析场景生成 architecture claim
|
|
1753
|
+
const _evWorkflowIntent = ctx.route_decision?.workflow_intent ?? ctx.classification?.route_decision?.workflow_intent;
|
|
1754
|
+
const _evIntentText = (ctx.intent ?? "").toLowerCase();
|
|
1755
|
+
const _isArchitectureContext = _evWorkflowIntent === "architecture_design"
|
|
1756
|
+
|| _evWorkflowIntent === "existing_system_gap_analysis"
|
|
1757
|
+
|| _evRoute === "artifact_generation"
|
|
1758
|
+
|| /架构|architecture|系统设计|技术方案|现有系统|差距分析|gap.?analysis/i.test(_evIntentText);
|
|
1759
|
+
if (_isArchitectureContext) {
|
|
1760
|
+
_evClaims.push({
|
|
1761
|
+
id: "claim-expand-1",
|
|
1762
|
+
category: "architecture",
|
|
1763
|
+
claim_text: "技术方案基于现有系统分析",
|
|
1764
|
+
evidence_ids: _evg.registry.query({}).filter((e) => e.evidence_role && e.evidence_role !== "template_guidance" && e.evidence_role !== "classification").map((e) => e.id),
|
|
1765
|
+
is_uncertain: false,
|
|
1766
|
+
risk_level: _evRisk,
|
|
1767
|
+
});
|
|
1768
|
+
}
|
|
1769
|
+
const _evVerify = _evg.verifier.verify(_evClaims, _evRisk);
|
|
1770
|
+
const _evMatrix = _evg.builder.buildContext(_evClaims, {
|
|
1771
|
+
target_claims: _evClaims.map((c) => c.claim_text),
|
|
1772
|
+
source_types: [], keywords: [], max_results: 10,
|
|
1773
|
+
});
|
|
1774
|
+
_evMatrix.task_id = args.task_id;
|
|
1775
|
+
const _evGate = _evg.gate.evaluate(_evMatrix, _evRisk);
|
|
1776
|
+
// 写回 TaskContext(blocked 也保存)
|
|
1777
|
+
await taskContext.setEvidenceGroundingResult(args.task_id, {
|
|
1778
|
+
evidence_matrix: _evMatrix,
|
|
1779
|
+
evidence_gate_result: _evGate,
|
|
1780
|
+
unsupported_claims: _evGate.unsupported_claims,
|
|
1781
|
+
conflict_resolutions: _evMatrix.conflicts,
|
|
1782
|
+
});
|
|
1783
|
+
if (!_evGate.allowed) {
|
|
1784
|
+
return {
|
|
1785
|
+
result: {
|
|
1786
|
+
error: `证据驱动门禁阻断: ${_evGate.reason_zh}`,
|
|
1787
|
+
diagnostic_code: _evGate.diagnostic_code,
|
|
1788
|
+
reason_zh: _evGate.reason_zh,
|
|
1789
|
+
unsupported_claims: _evGate.unsupported_claims,
|
|
1790
|
+
missing_evidence: _evGate.missing_evidence,
|
|
1791
|
+
status: "blocked",
|
|
1792
|
+
recovery: "请提供项目文件、命令输出或其他权威证据支撑关键声明后重新 sf_expand",
|
|
1793
|
+
},
|
|
1794
|
+
};
|
|
1795
|
+
}
|
|
1796
|
+
if (_evGate.requires_user_confirmation.length > 0) {
|
|
1797
|
+
advisories.evidence_advisory = {
|
|
1798
|
+
level: "requires_confirmation",
|
|
1799
|
+
items: _evGate.requires_user_confirmation,
|
|
1800
|
+
diagnostic_code: _evGate.diagnostic_code,
|
|
1801
|
+
};
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
else {
|
|
1805
|
+
// 低风险通用问答:标注为通用建议
|
|
1806
|
+
advisories.evidence_advisory = "通用建议,非项目事实;证据驱动门禁低风险放行";
|
|
1807
|
+
}
|
|
1808
|
+
// 配置优先级警告
|
|
1365
1809
|
if (expansion.config_resolution_reports && expansion.config_resolution_reports.length > 0) {
|
|
1366
1810
|
const configWarnings = expansion.config_resolution_reports
|
|
1367
1811
|
.filter(r => r.conflicts.length > 0)
|
|
@@ -1428,6 +1872,111 @@ export async function registerTools(server, deps) {
|
|
|
1428
1872
|
result: { error: "任务不存在" },
|
|
1429
1873
|
};
|
|
1430
1874
|
}
|
|
1875
|
+
// 问题六十二: 设计产物验证必须读取用户项目真实文件,不接受占位合同自证通过。
|
|
1876
|
+
const verifyWorkflowIntent = ctx.route_decision?.workflow_intent ?? ctx.classification?.route_decision?.workflow_intent;
|
|
1877
|
+
const touchesDesignArtifacts = args.changed_files.some((file) => /docs\/architecture\/|docs\/api\/|openapi|db\/(?:migrations|schema)|架构设计|数据库设计|API接口规格/i.test(file));
|
|
1878
|
+
if (verifyWorkflowIntent === "architecture_design" || touchesDesignArtifacts) {
|
|
1879
|
+
const designModule = await lazyDesignArtifactPack();
|
|
1880
|
+
const designPack = ctx.design_artifact_pack ?? designModule.createDesignArtifactPack(args.task_id);
|
|
1881
|
+
const designVerification = designModule.verifyDesignArtifactPack(projectPath, designPack);
|
|
1882
|
+
ctx.design_artifact_pack = {
|
|
1883
|
+
...designPack,
|
|
1884
|
+
status: designVerification.status,
|
|
1885
|
+
findings: designVerification.findings,
|
|
1886
|
+
baseline_hashes: designVerification.hashes,
|
|
1887
|
+
verified_at: new Date().toISOString(),
|
|
1888
|
+
};
|
|
1889
|
+
await taskContext.save(ctx);
|
|
1890
|
+
if (!designVerification.passed) {
|
|
1891
|
+
return {
|
|
1892
|
+
result: {
|
|
1893
|
+
error: "设计产物包复验未通过,不得继续生成编码或交付结论",
|
|
1894
|
+
status: "blocked",
|
|
1895
|
+
diagnostic_code: "SF-DESIGN-PACK-VERIFY-FAILED",
|
|
1896
|
+
design_artifact_findings: designVerification.findings,
|
|
1897
|
+
checked_files: designVerification.checked_files,
|
|
1898
|
+
recovery: "修复设计产物、补充用户确认并重新执行 sf_verify;不得只提交报告绕过缺口",
|
|
1899
|
+
},
|
|
1900
|
+
};
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
// 问题六十三: 模板契约验证 — 按文件逐一匹配契约并校验
|
|
1904
|
+
const sacModule = await lazyStandardAssetContract();
|
|
1905
|
+
const formalArtifactContract = sacModule.matchTemplateContract({
|
|
1906
|
+
output_artifact_kind: ctx.artifact_output?.kind,
|
|
1907
|
+
workflow_intent: verifyWorkflowIntent,
|
|
1908
|
+
route_decision: ctx.route_decision?.workflow_intent,
|
|
1909
|
+
});
|
|
1910
|
+
if (formalArtifactContract || !sacModule.isLowRiskTask({
|
|
1911
|
+
route_decision: verifyWorkflowIntent ?? ctx.classification?.route_decision?.workflow_intent,
|
|
1912
|
+
workflow_intent: verifyWorkflowIntent,
|
|
1913
|
+
changed_files: args.changed_files,
|
|
1914
|
+
})) {
|
|
1915
|
+
for (const changedFile of args.changed_files) {
|
|
1916
|
+
const absFile = path.join(projectPath, changedFile);
|
|
1917
|
+
if (!fss.existsSync(absFile) || !/\.md$/.test(changedFile))
|
|
1918
|
+
continue;
|
|
1919
|
+
// 按实际文件路径匹配契约(不再使用 changed_files[0] 的契约校验全部文件)
|
|
1920
|
+
const perFileContract = sacModule.matchTemplateContract({
|
|
1921
|
+
output_artifact_kind: ctx.artifact_output?.kind,
|
|
1922
|
+
workflow_intent: verifyWorkflowIntent,
|
|
1923
|
+
route_decision: ctx.route_decision?.workflow_intent,
|
|
1924
|
+
file_path: changedFile,
|
|
1925
|
+
});
|
|
1926
|
+
if (!perFileContract)
|
|
1927
|
+
continue;
|
|
1928
|
+
const content = fss.readFileSync(absFile, "utf-8");
|
|
1929
|
+
// 草稿阻断下游消费 — 不再静默跳过
|
|
1930
|
+
if (sacModule.isDraftDocument(content)) {
|
|
1931
|
+
ctx.repair_reverify_directive = {
|
|
1932
|
+
contract_id: perFileContract.asset_id,
|
|
1933
|
+
file_path: changedFile,
|
|
1934
|
+
status: "draft_blocked",
|
|
1935
|
+
repair_suggestion: `文件 ${changedFile} 仍为草稿状态,草稿不可用于实现。请完善内容后重新验证。`,
|
|
1936
|
+
blocked: true,
|
|
1937
|
+
};
|
|
1938
|
+
await taskContext.save(ctx);
|
|
1939
|
+
return {
|
|
1940
|
+
result: {
|
|
1941
|
+
error: `草稿文件 ${changedFile} 不可用于实现,需完善后重新验证`,
|
|
1942
|
+
status: "blocked",
|
|
1943
|
+
diagnostic_code: "SF-CONTRACT-DRAFT",
|
|
1944
|
+
template_contract_id: perFileContract.asset_id,
|
|
1945
|
+
recovery: "完善草稿内容后重新执行 sf_verify",
|
|
1946
|
+
},
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
const contractResult = sacModule.verifyOutputAgainstContract(perFileContract, content, projectPath);
|
|
1950
|
+
if (!contractResult.passed) {
|
|
1951
|
+
const repairDirective = sacModule.createRepairReverifyDirective(perFileContract, contractResult);
|
|
1952
|
+
ctx.repair_reverify_directive = {
|
|
1953
|
+
contract_id: perFileContract.asset_id,
|
|
1954
|
+
file_path: changedFile,
|
|
1955
|
+
status: "repair_required",
|
|
1956
|
+
repair_suggestion: repairDirective.repair_suggestion,
|
|
1957
|
+
blocked: true,
|
|
1958
|
+
};
|
|
1959
|
+
await taskContext.save(ctx);
|
|
1960
|
+
return {
|
|
1961
|
+
result: {
|
|
1962
|
+
error: `文件 ${changedFile} 模板契约验证未通过,进入修复重验闭环`,
|
|
1963
|
+
status: "blocked",
|
|
1964
|
+
diagnostic_code: "SF-CONTRACT-0003",
|
|
1965
|
+
template_contract_id: perFileContract.asset_id,
|
|
1966
|
+
missing_fields: contractResult.missing_fields,
|
|
1967
|
+
messages: contractResult.messages,
|
|
1968
|
+
repair_suggestion: repairDirective.repair_suggestion,
|
|
1969
|
+
recovery: "修复文档缺口后重新执行 sf_verify;不得只报告不修复",
|
|
1970
|
+
},
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
// 全部契约验证通过 — 清零修复重验指令
|
|
1975
|
+
if (ctx.repair_reverify_directive) {
|
|
1976
|
+
delete ctx.repair_reverify_directive;
|
|
1977
|
+
await taskContext.save(ctx);
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1431
1980
|
// RouteDecision 合同验证 — 无条件,在状态预检之前
|
|
1432
1981
|
const rdFromCtx = ctx.route_decision ?? ctx.classification?.route_decision ?? null;
|
|
1433
1982
|
const wtFromCtx = ctx.workflow_trace ?? ctx.expansion?.workflow_trace ?? null;
|
|
@@ -1580,6 +2129,82 @@ export async function registerTools(server, deps) {
|
|
|
1580
2129
|
// 附加验证契约引用到返回结果
|
|
1581
2130
|
verifyPayload.verification_plan = vPlan;
|
|
1582
2131
|
verifyPayload.verification_result = vResult;
|
|
2132
|
+
// 问题六十:验证结论必须经过 FactClaimVerifier,不得把计划当结果
|
|
2133
|
+
{
|
|
2134
|
+
const { createEvidenceGroundingSystem, assessTaskRisk } = await import("../../engine/evidence_grounding_contract.js");
|
|
2135
|
+
const _vRoute = ctx.route_decision?.route ?? ctx.classification?.route_decision?.route;
|
|
2136
|
+
const _vRisk = assessTaskRisk(ctx.classification?.task_type, _vRoute, ctx.intent);
|
|
2137
|
+
if (_vRisk !== "low") {
|
|
2138
|
+
const _veg = createEvidenceGroundingSystem();
|
|
2139
|
+
// 只有真实执行结果才能作为 validation_result 证据
|
|
2140
|
+
const _hasRealPassed = ctx.verification_result && ctx.verification_result.status === "passed";
|
|
2141
|
+
if (_hasRealPassed) {
|
|
2142
|
+
_veg.registry.register({
|
|
2143
|
+
source_type: "validation_result",
|
|
2144
|
+
authority: "authoritative",
|
|
2145
|
+
freshness: "current",
|
|
2146
|
+
permission: "allowed",
|
|
2147
|
+
scope: "verification",
|
|
2148
|
+
description: `验证状态: ${ctx.verification_result.status}`,
|
|
2149
|
+
source_ref: `verification:${args.task_id}`,
|
|
2150
|
+
});
|
|
2151
|
+
}
|
|
2152
|
+
// 验证计划注册为 task_context,不冒充 validation_result
|
|
2153
|
+
_veg.registry.register({
|
|
2154
|
+
source_type: "task_context",
|
|
2155
|
+
authority: "supporting",
|
|
2156
|
+
freshness: "current",
|
|
2157
|
+
permission: "allowed",
|
|
2158
|
+
scope: "verification_plan",
|
|
2159
|
+
description: `验证计划: ${vPlan ? "已生成" : "未生成"}`,
|
|
2160
|
+
source_ref: `verification-plan:${args.task_id}`,
|
|
2161
|
+
});
|
|
2162
|
+
if (args.changed_files.length > 0) {
|
|
2163
|
+
_veg.registry.register({
|
|
2164
|
+
source_type: "project_file",
|
|
2165
|
+
authority: "authoritative",
|
|
2166
|
+
freshness: "current",
|
|
2167
|
+
permission: "allowed",
|
|
2168
|
+
scope: "changed_files",
|
|
2169
|
+
description: `变更文件: ${args.changed_files.join(", ")}`,
|
|
2170
|
+
source_ref: `files:${args.changed_files.join(",")}`,
|
|
2171
|
+
});
|
|
2172
|
+
}
|
|
2173
|
+
const _vClaims = [{
|
|
2174
|
+
id: "claim-verify-1",
|
|
2175
|
+
category: "validation_result",
|
|
2176
|
+
claim_text: "验证结果基于真实命令执行",
|
|
2177
|
+
evidence_ids: _veg.registry.query({ source_type: "validation_result" }).map((e) => e.id),
|
|
2178
|
+
is_uncertain: false,
|
|
2179
|
+
risk_level: _vRisk,
|
|
2180
|
+
}];
|
|
2181
|
+
const _vVerResult = _veg.verifier.verify(_vClaims, _vRisk);
|
|
2182
|
+
const _vMatrix = _veg.builder.buildContext(_vClaims, {
|
|
2183
|
+
target_claims: _vClaims.map((c) => c.claim_text),
|
|
2184
|
+
source_types: [], keywords: [], max_results: 10,
|
|
2185
|
+
});
|
|
2186
|
+
_vMatrix.task_id = args.task_id;
|
|
2187
|
+
const _vGate = _veg.gate.evaluate(_vMatrix, _vRisk);
|
|
2188
|
+
// 写回 TaskContext
|
|
2189
|
+
await taskContext.setEvidenceGroundingResult(args.task_id, {
|
|
2190
|
+
evidence_matrix: _vMatrix,
|
|
2191
|
+
evidence_gate_result: _vGate,
|
|
2192
|
+
unsupported_claims: _vGate.unsupported_claims,
|
|
2193
|
+
conflict_resolutions: _vMatrix.conflicts,
|
|
2194
|
+
});
|
|
2195
|
+
if (_vVerResult.unsupported.length > 0) {
|
|
2196
|
+
// 高风险:只有 plan 无 result → 写入 payload(不用 verifyExtras)
|
|
2197
|
+
verifyPayload._evidence_status = "not_verified";
|
|
2198
|
+
verifyPayload._evidence_reason = "验证结论需真实命令执行结果支撑,验证计划不能当作验证结果。请通过 sf_record_verification_execution 录入真实验证结果。";
|
|
2199
|
+
if (_vRisk === "high" || _vRisk === "critical") {
|
|
2200
|
+
verifyPayload._evidence_blocked = true;
|
|
2201
|
+
}
|
|
2202
|
+
else {
|
|
2203
|
+
verifyPayload._evidence_advisory = "验证结论需真实命令执行结果支撑,验证计划不能当作验证结果";
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
1583
2208
|
// 验证后核心体验评估
|
|
1584
2209
|
try {
|
|
1585
2210
|
const hasVerificationEvidence = (verifyResult.checks?.build?.length ?? 0) > 0 || (verifyResult.checks?.tests?.length ?? 0) > 0;
|
|
@@ -2044,6 +2669,103 @@ export async function registerTools(server, deps) {
|
|
|
2044
2669
|
};
|
|
2045
2670
|
});
|
|
2046
2671
|
// ── sf_deliver: 自动提交、推送、创建 PR ──
|
|
2672
|
+
// ── sf_accept: 记录任务验收证据(本地验收 + 产物确认) ──
|
|
2673
|
+
registerSafeTool("sf_accept", "记录任务验收证据,解除 sf_deliver 的本地验收门和产物确认门", AcceptSchema, async (args) => {
|
|
2674
|
+
const ctx = await taskContext.load(args.task_id);
|
|
2675
|
+
if (!ctx) {
|
|
2676
|
+
return { result: { error: "任务不存在" } };
|
|
2677
|
+
}
|
|
2678
|
+
const runMode = args.run_mode;
|
|
2679
|
+
const notes = String(args.acceptance_notes ?? "").trim();
|
|
2680
|
+
const confirmedBy = String(args.confirmed_by ?? "").trim();
|
|
2681
|
+
const confirmationRef = String(args.confirmation_ref ?? "").trim();
|
|
2682
|
+
if (args.confirm !== true || !confirmedBy || !confirmationRef || !notes) {
|
|
2683
|
+
return {
|
|
2684
|
+
result: {
|
|
2685
|
+
error: "验收必须包含显式确认、确认者、可审计确认引用和验收说明",
|
|
2686
|
+
diagnostic_code: "SF-ACCEPT-CONFIRMATION-REQUIRED",
|
|
2687
|
+
recovery_next_tools: ["sf_accept", "sf_status"],
|
|
2688
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
2689
|
+
},
|
|
2690
|
+
};
|
|
2691
|
+
}
|
|
2692
|
+
const currentVerification = ctx.verification_result ?? ctx.batch2_verification_result;
|
|
2693
|
+
if (currentVerification?.status !== "passed") {
|
|
2694
|
+
return {
|
|
2695
|
+
result: {
|
|
2696
|
+
error: "验收前必须已有真实执行并通过的 verification_result",
|
|
2697
|
+
diagnostic_code: "SF-ACCEPT-VERIFICATION-REQUIRED",
|
|
2698
|
+
recovery_next_tools: ["sf_verify", "sf_record_verification_execution", "sf_status"],
|
|
2699
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
2700
|
+
},
|
|
2701
|
+
};
|
|
2702
|
+
}
|
|
2703
|
+
const evidenceRef = `acceptance:user_confirmation:${confirmationRef}`;
|
|
2704
|
+
if (runMode === "manual_review") {
|
|
2705
|
+
const acceptanceModule = await lazyLocalAcceptance();
|
|
2706
|
+
if (!args.final_access) {
|
|
2707
|
+
return {
|
|
2708
|
+
result: {
|
|
2709
|
+
error: "manual_review 验收缺少 final_access 真实访问证据",
|
|
2710
|
+
diagnostic_code: "SF-ACCEPT-FINAL-ACCESS-REQUIRED",
|
|
2711
|
+
recovery_next_tools: ["sf_accept", "sf_status"],
|
|
2712
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
2713
|
+
},
|
|
2714
|
+
};
|
|
2715
|
+
}
|
|
2716
|
+
const finalAccessResult = acceptanceModule.validateFinalAccess(args.final_access, "local_dev_server");
|
|
2717
|
+
if (!finalAccessResult.passed) {
|
|
2718
|
+
return {
|
|
2719
|
+
result: {
|
|
2720
|
+
error: `manual_review 验收证据不完整: ${finalAccessResult.blocking_reasons.join("; ")}`,
|
|
2721
|
+
diagnostic_code: "SF-ACCEPT-FINAL-ACCESS-INVALID",
|
|
2722
|
+
recovery_next_tools: ["sf_accept", "sf_status"],
|
|
2723
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
2724
|
+
},
|
|
2725
|
+
};
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
// 设置本地验收证据
|
|
2729
|
+
ctx.local_acceptance_evidence = {
|
|
2730
|
+
status: runMode === "manual_review" ? "passed" : "not_applicable",
|
|
2731
|
+
run_mode: runMode,
|
|
2732
|
+
confirmed_by: confirmedBy,
|
|
2733
|
+
confirmation_ref: confirmationRef,
|
|
2734
|
+
final_access: args.final_access ?? {
|
|
2735
|
+
frontend_urls: [],
|
|
2736
|
+
backend_urls: [],
|
|
2737
|
+
docs_or_swagger_urls: [],
|
|
2738
|
+
start_commands: [],
|
|
2739
|
+
stop_commands: [],
|
|
2740
|
+
running_status: "not_started",
|
|
2741
|
+
manual_review_steps_zh: [notes],
|
|
2742
|
+
known_limits_zh: [],
|
|
2743
|
+
},
|
|
2744
|
+
evidence_refs: [evidenceRef],
|
|
2745
|
+
};
|
|
2746
|
+
await taskContext.save(ctx);
|
|
2747
|
+
let updatedCtx = ctx;
|
|
2748
|
+
// 产物确认必须经过统一生命周期校验,不直接改写 status。
|
|
2749
|
+
if (ctx.artifact_output && ctx.artifact_output.status === "verified") {
|
|
2750
|
+
updatedCtx = await taskContext.updateArtifactStatus(args.task_id, {
|
|
2751
|
+
status: "accepted",
|
|
2752
|
+
evidenceRef,
|
|
2753
|
+
hasAcceptance: true,
|
|
2754
|
+
}) ?? ctx;
|
|
2755
|
+
}
|
|
2756
|
+
return {
|
|
2757
|
+
result: {
|
|
2758
|
+
task_id: args.task_id,
|
|
2759
|
+
acceptance_status: "passed",
|
|
2760
|
+
run_mode: runMode,
|
|
2761
|
+
evidence_ref: evidenceRef,
|
|
2762
|
+
artifact_transition: updatedCtx.artifact_output
|
|
2763
|
+
? `${updatedCtx.artifact_output.status}`
|
|
2764
|
+
: "no_artifact",
|
|
2765
|
+
},
|
|
2766
|
+
};
|
|
2767
|
+
});
|
|
2768
|
+
// ── sf_deliver: 自动提交、推送、创建 PR ──
|
|
2047
2769
|
registerSafeTool("sf_deliver", "验收后自动提交代码、推送、创建 PR 和生成变更日志", DeliverSchema, async (args) => {
|
|
2048
2770
|
const ctx = await taskContext.load(args.task_id);
|
|
2049
2771
|
if (!ctx) {
|
|
@@ -2056,6 +2778,19 @@ export async function registerTools(server, deps) {
|
|
|
2056
2778
|
const h4DeliverWarning = !deliverIntegrity.clean
|
|
2057
2779
|
? { warning: `H4 advisory: ${deliverIntegrity.message}`, dirty_files: deliverIntegrity.dirty_files }
|
|
2058
2780
|
: undefined;
|
|
2781
|
+
// 模板契约修复指令优先于通用产物状态提示,确保客户端获得可执行的修复重验路径。
|
|
2782
|
+
if (ctx.repair_reverify_directive) {
|
|
2783
|
+
return {
|
|
2784
|
+
result: {
|
|
2785
|
+
error: "存在未清零的模板契约修复指令,需完成修复重验后才能交付",
|
|
2786
|
+
diagnostic_code: "SF-CONTRACT-0003",
|
|
2787
|
+
repair_directive: ctx.repair_reverify_directive,
|
|
2788
|
+
recovery: "修复文档缺口后重新执行 sf_verify,验证通过后 repair_reverify_directive 自动清零",
|
|
2789
|
+
recovery_next_tools: ["sf_learn", "sf_verify", "sf_status"],
|
|
2790
|
+
recovery_forbidden_tools: ["sf_deliver", "sf_scaffold", "sf_classify", "sf_expand"],
|
|
2791
|
+
},
|
|
2792
|
+
};
|
|
2793
|
+
}
|
|
2059
2794
|
// 产物状态门控: deliver 需要产物状态为 accepted 且有证据
|
|
2060
2795
|
if (ctx.artifact_output) {
|
|
2061
2796
|
const status = ctx.artifact_output.status;
|
|
@@ -2091,6 +2826,17 @@ export async function registerTools(server, deps) {
|
|
|
2091
2826
|
}
|
|
2092
2827
|
}
|
|
2093
2828
|
}
|
|
2829
|
+
// 问题六十二: 依赖设计产物的任务只有 implementation_ready 后才可交付。
|
|
2830
|
+
if (ctx.design_artifact_pack && ctx.design_artifact_pack.status !== "implementation_ready") {
|
|
2831
|
+
return {
|
|
2832
|
+
result: {
|
|
2833
|
+
error: `设计产物包状态为 ${ctx.design_artifact_pack.status},未达到 implementation_ready,不得交付`,
|
|
2834
|
+
diagnostic_code: "SF-DESIGN-PACK-NOT-READY",
|
|
2835
|
+
findings: ctx.design_artifact_pack.findings,
|
|
2836
|
+
recovery: "请完成设计产物真实复验并修复所有阻断项后重新交付",
|
|
2837
|
+
},
|
|
2838
|
+
};
|
|
2839
|
+
}
|
|
2094
2840
|
// 交付 lease 互斥检查
|
|
2095
2841
|
const leaseModule = await lazyWorkspaceLease();
|
|
2096
2842
|
const deliverLease = leaseModule.acquireLease(args.task_id, "delivery", [projectPath]);
|
|
@@ -2126,6 +2872,7 @@ export async function registerTools(server, deps) {
|
|
|
2126
2872
|
const metricsData = await (await lazyObservability()).collectDeliveryMetricSamples(taskContext.getStateDir());
|
|
2127
2873
|
// acceptanceConfig: 从项目配置推断 project_run_mode
|
|
2128
2874
|
const projectHasFrontend = config.tech_stack.frontend.lang && config.tech_stack.frontend.lang !== "none";
|
|
2875
|
+
const projectHasBackend = config.tech_stack.backend.lang && config.tech_stack.backend.lang !== "none";
|
|
2129
2876
|
const readinessReport = drModule.evaluateDeliveryReadiness(args.task_id, currentVResult, guardFindings, true, // scope_check — 已在 sf_verify 写入护栏中检查
|
|
2130
2877
|
deliverLease.conflicts.length === 0, // lease_check — 无冲突即通过
|
|
2131
2878
|
true, // privacy_check — 已在任务创建时脱敏
|
|
@@ -2155,7 +2902,7 @@ export async function registerTools(server, deps) {
|
|
|
2155
2902
|
const localAcceptanceGate = await checkLocalAcceptanceGate({
|
|
2156
2903
|
ctx,
|
|
2157
2904
|
hasFrontend: !!projectHasFrontend,
|
|
2158
|
-
hasBackend: !!
|
|
2905
|
+
hasBackend: !!projectHasBackend,
|
|
2159
2906
|
hasDockerCompose: false,
|
|
2160
2907
|
hasDockerfile: false,
|
|
2161
2908
|
});
|
|
@@ -2173,12 +2920,74 @@ export async function registerTools(server, deps) {
|
|
|
2173
2920
|
};
|
|
2174
2921
|
}
|
|
2175
2922
|
}
|
|
2923
|
+
// 问题六十:交付结论必须经过 UnsupportedClaimGate
|
|
2924
|
+
{
|
|
2925
|
+
const { createEvidenceGroundingSystem, assessTaskRisk } = await import("../../engine/evidence_grounding_contract.js");
|
|
2926
|
+
const _dRoute = ctx.route_decision?.route ?? ctx.classification?.route_decision?.route;
|
|
2927
|
+
const _dRisk = assessTaskRisk(ctx.classification?.task_type, _dRoute, ctx.intent);
|
|
2928
|
+
if (_dRisk !== "low") {
|
|
2929
|
+
const _deg = createEvidenceGroundingSystem();
|
|
2930
|
+
// 注册验证结果和交付上下文
|
|
2931
|
+
if (currentVResult) {
|
|
2932
|
+
_deg.registry.register({
|
|
2933
|
+
source_type: "validation_result",
|
|
2934
|
+
authority: "authoritative",
|
|
2935
|
+
freshness: "current",
|
|
2936
|
+
permission: "allowed",
|
|
2937
|
+
scope: "verification",
|
|
2938
|
+
description: `验证状态: ${currentVResult.status}`,
|
|
2939
|
+
source_ref: `verification:${args.task_id}`,
|
|
2940
|
+
});
|
|
2941
|
+
}
|
|
2942
|
+
_deg.registry.register({
|
|
2943
|
+
source_type: "task_context",
|
|
2944
|
+
authority: "authoritative",
|
|
2945
|
+
freshness: "current",
|
|
2946
|
+
permission: "allowed",
|
|
2947
|
+
scope: "delivery",
|
|
2948
|
+
description: "交付上下文",
|
|
2949
|
+
source_ref: `task:${args.task_id}`,
|
|
2950
|
+
});
|
|
2951
|
+
const _dClaims = [
|
|
2952
|
+
{
|
|
2953
|
+
id: "claim-deliver-1",
|
|
2954
|
+
category: "release_status",
|
|
2955
|
+
claim_text: "交付基于真实验证结果",
|
|
2956
|
+
evidence_ids: _deg.registry.query({ source_type: "validation_result" }).map((e) => e.id),
|
|
2957
|
+
is_uncertain: false,
|
|
2958
|
+
risk_level: _dRisk,
|
|
2959
|
+
},
|
|
2960
|
+
];
|
|
2961
|
+
const _dMatrix = _deg.builder.buildContext(_dClaims, { target_claims: ["交付验证"], source_types: ["validation_result", "task_context"], keywords: ["验证", "交付"], max_results: 10 });
|
|
2962
|
+
_dMatrix.task_id = args.task_id;
|
|
2963
|
+
const _dGateResult = _deg.gate.evaluate(_dMatrix, _dRisk);
|
|
2964
|
+
// 写回 TaskContext(blocked 也保存)
|
|
2965
|
+
await taskContext.setEvidenceGroundingResult(args.task_id, {
|
|
2966
|
+
evidence_matrix: _dMatrix,
|
|
2967
|
+
evidence_gate_result: _dGateResult,
|
|
2968
|
+
unsupported_claims: _dGateResult.unsupported_claims,
|
|
2969
|
+
conflict_resolutions: _dMatrix.conflicts,
|
|
2970
|
+
});
|
|
2971
|
+
if (!_dGateResult.allowed) {
|
|
2972
|
+
if (deliverLease.lease) {
|
|
2973
|
+
leaseModule.releaseLease(deliverLease.lease.lease_id);
|
|
2974
|
+
}
|
|
2975
|
+
return {
|
|
2976
|
+
result: {
|
|
2977
|
+
error: `证据驱动门禁未通过: ${_dGateResult.reason_zh}`,
|
|
2978
|
+
diagnostic_code: _dGateResult.diagnostic_code,
|
|
2979
|
+
unsupported_claims: _dGateResult.unsupported_claims,
|
|
2980
|
+
},
|
|
2981
|
+
};
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2176
2985
|
// 交付前检查 false completion(通过提取的主链路函数)
|
|
2177
2986
|
const cepNfcResult = await assessCepBeforeDelivery({
|
|
2178
2987
|
task_id: args.task_id,
|
|
2179
2988
|
verification_passed: currentVResult?.status === "passed",
|
|
2180
2989
|
build_passed: (currentVResult?.passed_commands ?? 0) > 0,
|
|
2181
|
-
browser_acceptance_passed: ctx.artifact_output?.status === "
|
|
2990
|
+
browser_acceptance_passed: ctx.artifact_output?.status === "accepted" || ctx.artifact_output === undefined,
|
|
2182
2991
|
guard_passed: guardFindings.length === 0 || guardFindings.every((f) => f.severity !== "hard_fail"),
|
|
2183
2992
|
evidence_sufficient: (currentVResult?.evidence_ids?.length ?? 0) > 0,
|
|
2184
2993
|
current_status: ctx.status === "done" ? "completed" : ctx.status,
|