soloforge 1.3.3 → 1.3.5
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 +19 -3
- package/dist/adapters/claude_code/server.js +1 -1
- package/dist/adapters/claude_code/server.js.map +1 -1
- package/dist/adapters/claude_code/tools.d.ts.map +1 -1
- package/dist/adapters/claude_code/tools.js +164 -44
- package/dist/adapters/claude_code/tools.js.map +1 -1
- package/dist/adapters/shared/workflow_template.js +2 -2
- package/dist/adapters/shared/workflow_template.js.map +1 -1
- package/dist/bin/soloforge.d.ts.map +1 -1
- package/dist/bin/soloforge.js +148 -1
- package/dist/bin/soloforge.js.map +1 -1
- package/dist/engine/asset_manifest.d.ts.map +1 -1
- package/dist/engine/asset_manifest.js +11 -0
- package/dist/engine/asset_manifest.js.map +1 -1
- package/dist/engine/backend_implementation_contract.d.ts +1 -1
- package/dist/engine/backend_implementation_contract.d.ts.map +1 -1
- package/dist/engine/backend_implementation_contract.js +22 -0
- package/dist/engine/backend_implementation_contract.js.map +1 -1
- package/dist/engine/brainstorm_contract.d.ts +1 -1
- package/dist/engine/brainstorm_contract.js +1 -1
- package/dist/engine/code_maintainability_observability_contract.d.ts +74 -0
- package/dist/engine/code_maintainability_observability_contract.d.ts.map +1 -0
- package/dist/engine/code_maintainability_observability_contract.js +711 -0
- package/dist/engine/code_maintainability_observability_contract.js.map +1 -0
- package/dist/engine/config_write_boundary.d.ts +29 -0
- package/dist/engine/config_write_boundary.d.ts.map +1 -0
- package/dist/engine/config_write_boundary.js +69 -0
- package/dist/engine/config_write_boundary.js.map +1 -0
- package/dist/engine/consumable_asset_registry.d.ts.map +1 -1
- package/dist/engine/consumable_asset_registry.js +49 -1
- package/dist/engine/consumable_asset_registry.js.map +1 -1
- package/dist/engine/contract_registry.js +1 -1
- package/dist/engine/diagnostic_registry.d.ts +13 -0
- package/dist/engine/diagnostic_registry.d.ts.map +1 -1
- package/dist/engine/diagnostic_registry.js +68 -0
- package/dist/engine/diagnostic_registry.js.map +1 -1
- package/dist/engine/dual_layer_mechanism_registry.d.ts.map +1 -1
- package/dist/engine/dual_layer_mechanism_registry.js +195 -2
- package/dist/engine/dual_layer_mechanism_registry.js.map +1 -1
- package/dist/engine/explicit_asset_registry.d.ts.map +1 -1
- package/dist/engine/explicit_asset_registry.js +134 -0
- package/dist/engine/explicit_asset_registry.js.map +1 -1
- package/dist/engine/extension_scenario_registry.js +4 -4
- package/dist/engine/extension_scenario_registry.js.map +1 -1
- package/dist/engine/foundation_scenario_runners.d.ts.map +1 -1
- package/dist/engine/foundation_scenario_runners.js +4 -2
- package/dist/engine/foundation_scenario_runners.js.map +1 -1
- package/dist/engine/historical_issue_mechanization_matrix.d.ts +28 -0
- package/dist/engine/historical_issue_mechanization_matrix.d.ts.map +1 -0
- package/dist/engine/historical_issue_mechanization_matrix.js +134 -0
- package/dist/engine/historical_issue_mechanization_matrix.js.map +1 -0
- package/dist/engine/implementation_roadmap_registry.d.ts.map +1 -1
- package/dist/engine/implementation_roadmap_registry.js +114 -13
- package/dist/engine/implementation_roadmap_registry.js.map +1 -1
- package/dist/engine/intent_expander.d.ts.map +1 -1
- package/dist/engine/intent_expander.js +151 -1
- package/dist/engine/intent_expander.js.map +1 -1
- package/dist/engine/knowledge_governance_gate.d.ts +38 -0
- package/dist/engine/knowledge_governance_gate.d.ts.map +1 -0
- package/dist/engine/knowledge_governance_gate.js +123 -0
- package/dist/engine/knowledge_governance_gate.js.map +1 -0
- package/dist/engine/log_governance.d.ts +25 -0
- package/dist/engine/log_governance.d.ts.map +1 -0
- package/dist/engine/log_governance.js +76 -0
- package/dist/engine/log_governance.js.map +1 -0
- package/dist/engine/mechanism_contract_registry.d.ts +1 -0
- package/dist/engine/mechanism_contract_registry.d.ts.map +1 -1
- package/dist/engine/mechanism_contract_registry.js +104 -0
- package/dist/engine/mechanism_contract_registry.js.map +1 -1
- package/dist/engine/mechanism_health_check.d.ts +23 -0
- package/dist/engine/mechanism_health_check.d.ts.map +1 -0
- package/dist/engine/mechanism_health_check.js +140 -0
- package/dist/engine/mechanism_health_check.js.map +1 -0
- package/dist/engine/next_action_planner.d.ts.map +1 -1
- package/dist/engine/next_action_planner.js +72 -4
- package/dist/engine/next_action_planner.js.map +1 -1
- package/dist/engine/observability.js +1 -1
- package/dist/engine/observability.js.map +1 -1
- package/dist/engine/project_knowledge_contract.d.ts +58 -0
- package/dist/engine/project_knowledge_contract.d.ts.map +1 -0
- package/dist/engine/project_knowledge_contract.js +298 -0
- package/dist/engine/project_knowledge_contract.js.map +1 -0
- package/dist/engine/project_knowledge_system_regression_matrix.d.ts +27 -0
- package/dist/engine/project_knowledge_system_regression_matrix.d.ts.map +1 -0
- package/dist/engine/project_knowledge_system_regression_matrix.js +295 -0
- package/dist/engine/project_knowledge_system_regression_matrix.js.map +1 -0
- package/dist/engine/release_issue_scenario_registry.d.ts.map +1 -1
- package/dist/engine/release_issue_scenario_registry.js +506 -95
- package/dist/engine/release_issue_scenario_registry.js.map +1 -1
- package/dist/engine/release_readiness_gate.d.ts +4 -0
- package/dist/engine/release_readiness_gate.d.ts.map +1 -1
- package/dist/engine/release_readiness_gate.js +643 -12
- package/dist/engine/release_readiness_gate.js.map +1 -1
- package/dist/engine/team_awareness.js +6 -6
- package/dist/engine/team_awareness.js.map +1 -1
- package/dist/engine/technology_decision.js +5 -5
- package/dist/engine/technology_decision.js.map +1 -1
- package/dist/engine/template_asset_contract_registry.d.ts.map +1 -1
- package/dist/engine/template_asset_contract_registry.js +6 -5
- package/dist/engine/template_asset_contract_registry.js.map +1 -1
- package/dist/engine/verifier.js +1 -1
- package/dist/engine/verifier.js.map +1 -1
- package/dist/engine/workflow_navigation_contract.d.ts +10 -0
- package/dist/engine/workflow_navigation_contract.d.ts.map +1 -1
- package/dist/knowledge/loader.d.ts +3 -1
- package/dist/knowledge/loader.d.ts.map +1 -1
- package/dist/knowledge/loader.js +2 -2
- package/dist/knowledge/loader.js.map +1 -1
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/templates/knowledge/acceptance_templates//344/273/243/347/240/201/346/263/250/351/207/212/344/270/216/346/227/245/345/277/227/351/252/214/346/224/266/346/250/241/346/235/277.md +78 -0
- package/templates/knowledge/acceptance_templates//351/200/232/347/224/250/350/264/250/351/207/217/351/252/214/346/224/266/346/270/205/345/215/225.md +1 -1
- package/templates/knowledge/acceptance_templates//351/207/215/346/236/204/346/226/271/346/241/210/346/250/241/347/211/210.md +1 -1
- package/templates/knowledge/domain//346/224/257/344/273/230/350/247/204/345/210/231.md +1 -1
- package/templates/knowledge/procedures//346/225/260/346/215/256/345/272/223/350/277/201/347/247/273/346/265/201/347/250/213.md +1 -1
- package/templates/knowledge/procedures//351/203/250/347/275/262/345/217/221/345/270/203/346/265/201/347/250/213.md +1 -1
- package/templates/knowledge/procedures//351/207/215/346/236/204/346/265/201/346/260/264/347/272/277.md +1 -1
- package/templates/knowledge/review//344/273/243/347/240/201/345/217/257/347/273/264/346/212/244/346/200/247/344/270/216/345/217/257/350/247/202/346/265/213/346/200/247/345/256/241/346/237/245.md +81 -0
- package/templates/knowledge/review_rules//344/272/244/344/273/230/345/256/214/345/244/207/346/200/247/345/256/241/346/237/245/350/247/204/345/210/231.md +1 -1
- package/templates/knowledge/review_rules//350/264/250/351/207/217/345/256/241/346/237/245/350/247/204/345/210/231.md +3 -3
- package/templates/knowledge/rules//344/273/243/347/240/201/346/263/250/351/207/212/344/270/216/346/227/245/345/277/227/345/245/221/347/272/246/350/247/204/345/210/231.md +150 -0
- package/templates/knowledge/rules//346/225/217/346/204/237/344/277/241/346/201/257/346/227/245/345/277/227/350/247/204/345/210/231.md +69 -0
- package/templates/knowledge/rules//346/227/245/345/277/227/346/262/273/347/220/206/350/247/204/345/210/231.md +49 -0
- package/templates/knowledge/rules//346/234/272/345/210/266/350/207/252/346/262/273/347/220/206/350/247/204/345/210/231.md +48 -0
- package/templates/knowledge/rules//346/240/270/345/277/203/344/275/223/351/252/214/345/216/237/345/210/231.md +1 -1
- package/templates/knowledge/rules//346/240/270/345/277/203/345/267/245/347/250/213/346/211/247/350/241/214/345/216/237/345/210/231.md +2 -2
- package/templates/knowledge/rules//346/274/224/350/277/233/345/233/236/345/275/222/351/227/250/346/216/247/350/247/204/345/210/231.md +1 -1
- package/templates/knowledge/rules//347/237/245/350/257/206/346/262/273/347/220/206/350/247/204/345/210/231.md +50 -0
- package/templates/knowledge/rules//351/205/215/347/275/256/350/220/275/347/233/230/350/276/271/347/225/214/350/247/204/345/210/231.md +47 -0
- package/templates/patterns/Git/346/223/215/344/275/234/350/247/204/350/214/203.md +1 -1
- package/templates/scaffolds/react/Form.tsx.hbs +11 -3
- package/templates/scaffolds/react/List.tsx.hbs +11 -3
- package/templates/scaffolds/react/Page.tsx.hbs +1 -1
- package/templates/scaffolds/react/types.ts.hbs +4 -1
- package/templates/scaffolds/spring-boot/Controller.java.hbs +18 -4
- package/templates/scaffolds/spring-boot/DTO.java.hbs +4 -1
- package/templates/scaffolds/spring-boot/Entity.java.hbs +8 -3
- package/templates/scaffolds/spring-boot/Mapper.java.hbs +4 -1
- package/templates/scaffolds/spring-boot/ServiceImpl.java.hbs +34 -10
- package/templates/scaffolds/spring-boot/ServiceTest.java.hbs +0 -1
|
@@ -67,121 +67,314 @@ function confirmDecisionWorkshopFromResponse(expResult) {
|
|
|
67
67
|
/**
|
|
68
68
|
* 发布问题全量场景定义。
|
|
69
69
|
*/
|
|
70
|
+
/** 架构研讨场景的完整技术决策契约,确保证据门禁和决策主权门禁都能通过 */
|
|
71
|
+
function makeTechnologyDecisionContract(taskId) {
|
|
72
|
+
return {
|
|
73
|
+
decision_id: `td-${taskId}`,
|
|
74
|
+
decision_scope: "system_architecture",
|
|
75
|
+
options: [
|
|
76
|
+
{ option_id: "microservices", description: "微服务架构", pros: ["独立部署"], cons: ["运维复杂"], risk_level: "medium" },
|
|
77
|
+
{ option_id: "monolith", description: "单体架构", pros: ["简单"], cons: ["扩展受限"], risk_level: "low" },
|
|
78
|
+
],
|
|
79
|
+
recommended_option: "microservices",
|
|
80
|
+
evidence: ["技术选型评估", "团队经验评估"],
|
|
81
|
+
falsification: ["性能测试不达标"],
|
|
82
|
+
failure_conditions: ["交付延迟超过2周"],
|
|
83
|
+
human_gate_required: true,
|
|
84
|
+
executable_without_human: false,
|
|
85
|
+
human_gate_evidence: "用户确认技术选型",
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** 架构研讨场景的第一性原理帧,确保高影响意图通过第一性原理门禁 */
|
|
89
|
+
function makeFirstPrinciplesFrame(taskId) {
|
|
90
|
+
return {
|
|
91
|
+
problem_id: `fp-${taskId}`,
|
|
92
|
+
user_goal: "为新系统生成架构设计文档",
|
|
93
|
+
fundamental_need: "系统化的架构设计,支撑后续开发",
|
|
94
|
+
known_facts: ["项目为新系统", "需要架构设计文档", "涉及微服务架构选型"],
|
|
95
|
+
assumptions: ["团队具备微服务开发经验", "基础设施支持容器化部署"],
|
|
96
|
+
non_negotiable_constraints: ["必须支持水平扩展", "技术栈基于 TypeScript"],
|
|
97
|
+
candidate_solutions: ["微服务架构", "单体模块化架构"],
|
|
98
|
+
simplest_viable_solution: "单体模块化架构",
|
|
99
|
+
falsification_questions: ["性能测试是否满足要求", "团队规模是否支撑微服务运维"],
|
|
100
|
+
chosen_solution: "微服务架构",
|
|
101
|
+
why_not_legacy_path: "遗留方案无法满足水平扩展需求",
|
|
102
|
+
first_principles_status: "verified",
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** 为架构研讨场景注入技术决策契约和第一性原理帧,确保证据门禁、决策主权门禁和第一性原理门禁都能通过 */
|
|
106
|
+
async function injectTechDecisionForWorkshop(harness, taskId) {
|
|
107
|
+
const ctx = await harness.taskContext.load(taskId);
|
|
108
|
+
if (!ctx)
|
|
109
|
+
return null;
|
|
110
|
+
ctx.technology_decision_contract = makeTechnologyDecisionContract(taskId);
|
|
111
|
+
ctx.first_principles_frame = makeFirstPrinciplesFrame(taskId);
|
|
112
|
+
await harness.taskContext.save(ctx);
|
|
113
|
+
return ctx;
|
|
114
|
+
}
|
|
70
115
|
const RELEASE_ISSUE_SCENARIOS = [
|
|
71
|
-
// ── 问题六十一:
|
|
72
|
-
// 场景 1:
|
|
116
|
+
// ── 问题六十一: 架构决策研讨 — 真实 sf_classify→sf_expand 主链路 ──
|
|
117
|
+
// 场景 1: greenfield 架构设计 → 完整闭环:阻断 → 全部确认 → 放行
|
|
73
118
|
{
|
|
74
|
-
scenario_id: "release-scenario-architecture-workshop-
|
|
119
|
+
scenario_id: "release-scenario-architecture-workshop-greenfield",
|
|
75
120
|
covering_problem: "problem-61",
|
|
76
|
-
test_files: ["tests/
|
|
77
|
-
production_entrypoint: "
|
|
78
|
-
expected_outcome: "
|
|
121
|
+
test_files: ["tests/engine/architecture_decision_workshop.test.ts"],
|
|
122
|
+
production_entrypoint: "sf_classify → sf_expand → confirm all → sf_expand",
|
|
123
|
+
expected_outcome: "greenfield 架构设计: sf_expand 阻断(六域未确认) → 全部确认+输出确认 → 二次 sf_expand 放行",
|
|
79
124
|
runner: async () => {
|
|
80
|
-
const {
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
125
|
+
const { createToolHarness } = await import("./release_tool_harness.js");
|
|
126
|
+
const harness = await createToolHarness();
|
|
127
|
+
try {
|
|
128
|
+
const clsRaw = await harness.callTool("sf_classify", { intent: "为新系统生成架构设计文档" });
|
|
129
|
+
const cls = harness.parseResult(clsRaw);
|
|
130
|
+
const taskId = cls.task_id;
|
|
131
|
+
if (!taskId)
|
|
132
|
+
return { scenario_id: "release-scenario-architecture-workshop-greenfield", status: "fail", error: "sf_classify 未返回 task_id" };
|
|
133
|
+
if (!await injectTechDecisionForWorkshop(harness, taskId))
|
|
134
|
+
return { scenario_id: "release-scenario-architecture-workshop-greenfield", status: "fail", error: "task context load failed" };
|
|
135
|
+
const exp1Raw = await harness.callTool("sf_expand", { task_id: taskId });
|
|
136
|
+
const exp1 = harness.parseResult(exp1Raw);
|
|
137
|
+
if (exp1.status !== "awaiting_confirmation")
|
|
138
|
+
return { scenario_id: "release-scenario-architecture-workshop-greenfield", status: "fail", error: `expected awaiting_confirmation, got status=${exp1.status}` };
|
|
139
|
+
const workshop = exp1.architecture_decision_workshop;
|
|
140
|
+
if (!workshop)
|
|
141
|
+
return { scenario_id: "release-scenario-architecture-workshop-greenfield", status: "fail", error: "sf_expand 未返回 architecture_decision_workshop" };
|
|
142
|
+
const domainCount = Object.keys(workshop.domains ?? {}).length;
|
|
143
|
+
if (domainCount < 6)
|
|
144
|
+
return { scenario_id: "release-scenario-architecture-workshop-greenfield", status: "fail", error: `expected >=6 domains, got ${domainCount}` };
|
|
145
|
+
// 全部域确认 + document_output_confirmation_ref
|
|
146
|
+
for (const key of Object.keys(workshop.domains ?? {})) {
|
|
147
|
+
workshop.domains[key].status = "confirmed";
|
|
148
|
+
workshop.domains[key].user_confirmation_ref = `confirm:${key}`;
|
|
149
|
+
}
|
|
150
|
+
workshop.document_output_confirmation_ref = "confirm:output";
|
|
151
|
+
const exp2Raw = await harness.callTool("sf_expand", { task_id: taskId, architecture_decision_workshop: workshop });
|
|
152
|
+
const exp2 = harness.parseResult(exp2Raw);
|
|
153
|
+
if (exp2.status === "awaiting_confirmation" || exp2.status === "blocked")
|
|
154
|
+
return { scenario_id: "release-scenario-architecture-workshop-greenfield", status: "fail", error: `second expand still blocked: status=${exp2.status}, error=${exp2.error ?? "none"}` };
|
|
155
|
+
const trace = await harness.collectTrace();
|
|
156
|
+
return {
|
|
157
|
+
scenario_id: "release-scenario-architecture-workshop-greenfield",
|
|
158
|
+
status: "pass",
|
|
159
|
+
evidence: `sf_classify→sf_expand(awaiting_confirmation,workshop=true,domains=${domainCount})→all confirm→sf_expand(pass)`,
|
|
160
|
+
production_trace: trace,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
harness.cleanup();
|
|
165
|
+
}
|
|
92
166
|
},
|
|
93
167
|
},
|
|
94
|
-
// 场景 2:
|
|
168
|
+
// 场景 2: existing_system 架构设计被阻断;补充确认+证据后放行
|
|
95
169
|
{
|
|
96
|
-
scenario_id: "release-scenario-architecture-workshop-
|
|
170
|
+
scenario_id: "release-scenario-architecture-workshop-existing-system",
|
|
97
171
|
covering_problem: "problem-61",
|
|
98
|
-
test_files: ["tests/
|
|
99
|
-
production_entrypoint: "
|
|
100
|
-
expected_outcome: "
|
|
172
|
+
test_files: ["tests/adapters/architecture_design_workshop_mainpath.test.ts"],
|
|
173
|
+
production_entrypoint: "sf_classify → sf_expand → confirm workshop with evidence → sf_expand",
|
|
174
|
+
expected_outcome: "existing_system 架构设计 sf_expand 返回 workshop + awaiting_confirmation;补入确认和证据后放行",
|
|
101
175
|
runner: async () => {
|
|
102
|
-
const {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
176
|
+
const { createToolHarness } = await import("./release_tool_harness.js");
|
|
177
|
+
const harness = await createToolHarness({ copyKnowledge: true });
|
|
178
|
+
try {
|
|
179
|
+
const fs = await import("node:fs");
|
|
180
|
+
const srcDir = `${harness.tmpDir}/src`;
|
|
181
|
+
fs.mkdirSync(srcDir, { recursive: true });
|
|
182
|
+
fs.writeFileSync(`${srcDir}/index.ts`, "export {}");
|
|
183
|
+
fs.writeFileSync(`${harness.tmpDir}/package.json`, '{"name":"existing"}');
|
|
184
|
+
const clsRaw = await harness.callTool("sf_classify", { intent: "基于现有系统进行架构设计" });
|
|
185
|
+
const cls = harness.parseResult(clsRaw);
|
|
186
|
+
const taskId = cls.task_id;
|
|
187
|
+
if (!taskId)
|
|
188
|
+
return { scenario_id: "release-scenario-architecture-workshop-existing-system", status: "fail", error: "sf_classify 未返回 task_id" };
|
|
189
|
+
// 提供完整技术决策契约,确保证据门禁和决策主权门禁通过
|
|
190
|
+
if (!await injectTechDecisionForWorkshop(harness, taskId))
|
|
191
|
+
return { scenario_id: "release-scenario-architecture-workshop-existing-system", status: "fail", error: "task context load failed" };
|
|
192
|
+
const exp1Raw = await harness.callTool("sf_expand", { task_id: taskId });
|
|
193
|
+
const exp1 = harness.parseResult(exp1Raw);
|
|
194
|
+
if (exp1.status !== "awaiting_confirmation")
|
|
195
|
+
return { scenario_id: "release-scenario-architecture-workshop-existing-system", status: "fail", error: `expected awaiting_confirmation, got status=${exp1.status}` };
|
|
196
|
+
const workshop = exp1.architecture_decision_workshop;
|
|
197
|
+
if (!workshop)
|
|
198
|
+
return { scenario_id: "release-scenario-architecture-workshop-existing-system", status: "fail", error: "sf_expand 未返回 architecture_decision_workshop" };
|
|
199
|
+
// 全部域确认 + 补齐前置证据
|
|
200
|
+
for (const key of Object.keys(workshop.domains ?? {})) {
|
|
201
|
+
workshop.domains[key].status = "confirmed";
|
|
202
|
+
workshop.domains[key].user_confirmation_ref = `confirm:${key}`;
|
|
203
|
+
}
|
|
204
|
+
workshop.prerequisite_evidence_refs = ["现状分析报告", "差距分析文档"];
|
|
205
|
+
workshop.document_output_confirmation_ref = "confirm:output";
|
|
206
|
+
const exp2Raw = await harness.callTool("sf_expand", { task_id: taskId, architecture_decision_workshop: workshop });
|
|
207
|
+
const exp2 = harness.parseResult(exp2Raw);
|
|
208
|
+
if ((exp2.status === "awaiting_confirmation" || exp2.status === "blocked") && exp2.architecture_decision_workshop)
|
|
209
|
+
return { scenario_id: "release-scenario-architecture-workshop-existing-system", status: "fail", error: `second expand still blocked: ${JSON.stringify(exp2.blocking_findings ?? []).slice(0, 200)}` };
|
|
210
|
+
const trace = await harness.collectTrace();
|
|
211
|
+
return {
|
|
212
|
+
scenario_id: "release-scenario-architecture-workshop-existing-system",
|
|
213
|
+
status: "pass",
|
|
214
|
+
evidence: `sf_classify→sf_expand(awaiting_confirmation,workshop=true,domains=${Object.keys(workshop.domains ?? {}).length})→confirm all+evidence→sf_expand(${exp2.status ?? "pass"})`,
|
|
215
|
+
production_trace: trace,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
finally {
|
|
219
|
+
harness.cleanup();
|
|
220
|
+
}
|
|
113
221
|
},
|
|
114
222
|
},
|
|
115
|
-
// 场景 3:
|
|
223
|
+
// 场景 3: 部分域确认 → 仍 blocked
|
|
116
224
|
{
|
|
117
225
|
scenario_id: "release-scenario-architecture-workshop-confirmation-block",
|
|
118
226
|
covering_problem: "problem-61",
|
|
119
227
|
test_files: ["tests/adapters/architecture_design_workshop_mainpath.test.ts"],
|
|
120
|
-
production_entrypoint: "
|
|
121
|
-
expected_outcome: "
|
|
228
|
+
production_entrypoint: "sf_classify → sf_expand → partial confirm → sf_expand",
|
|
229
|
+
expected_outcome: "部分域确认后仍 blocked,返回 next_domain;全部确认后放行",
|
|
122
230
|
runner: async () => {
|
|
123
|
-
const {
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
status
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
231
|
+
const { createToolHarness } = await import("./release_tool_harness.js");
|
|
232
|
+
const harness = await createToolHarness();
|
|
233
|
+
try {
|
|
234
|
+
const clsRaw = await harness.callTool("sf_classify", { intent: "为新项目进行架构设计" });
|
|
235
|
+
const cls = harness.parseResult(clsRaw);
|
|
236
|
+
const taskId = cls.task_id;
|
|
237
|
+
if (!taskId)
|
|
238
|
+
return { scenario_id: "release-scenario-architecture-workshop-confirmation-block", status: "fail", error: "sf_classify 未返回 task_id" };
|
|
239
|
+
// 提供完整技术决策契约,确保证据门禁和决策主权门禁通过
|
|
240
|
+
if (!await injectTechDecisionForWorkshop(harness, taskId))
|
|
241
|
+
return { scenario_id: "release-scenario-architecture-workshop-confirmation-block", status: "fail", error: "task context load failed" };
|
|
242
|
+
const exp1Raw = await harness.callTool("sf_expand", { task_id: taskId });
|
|
243
|
+
const exp1 = harness.parseResult(exp1Raw);
|
|
244
|
+
if (exp1.status !== "awaiting_confirmation")
|
|
245
|
+
return { scenario_id: "release-scenario-architecture-workshop-confirmation-block", status: "fail", error: `expected awaiting_confirmation, got status=${exp1.status}` };
|
|
246
|
+
const workshop = exp1.architecture_decision_workshop;
|
|
247
|
+
if (!workshop)
|
|
248
|
+
return { scenario_id: "release-scenario-architecture-workshop-confirmation-block", status: "fail", error: "sf_expand 未返回 architecture_decision_workshop" };
|
|
249
|
+
// 只确认第一个域
|
|
250
|
+
const domainKeys = Object.keys(workshop.domains ?? {});
|
|
251
|
+
const confirmedCount = Math.min(1, domainKeys.length);
|
|
252
|
+
for (let i = 0; i < confirmedCount; i++) {
|
|
253
|
+
workshop.domains[domainKeys[i]].status = "confirmed";
|
|
254
|
+
workshop.domains[domainKeys[i]].user_confirmation_ref = `confirm:${domainKeys[i]}`;
|
|
255
|
+
}
|
|
256
|
+
workshop.document_output_confirmation_ref = "confirm:output";
|
|
257
|
+
const exp2Raw = await harness.callTool("sf_expand", { task_id: taskId, architecture_decision_workshop: workshop });
|
|
258
|
+
const exp2 = harness.parseResult(exp2Raw);
|
|
259
|
+
if (exp2.status !== "awaiting_confirmation")
|
|
260
|
+
return { scenario_id: "release-scenario-architecture-workshop-confirmation-block", status: "fail", error: `expected still awaiting_confirmation after partial confirm (${confirmedCount}/${domainKeys.length}), got status=${exp2.status}` };
|
|
261
|
+
// 全部确认后必须放行
|
|
262
|
+
for (const key of domainKeys) {
|
|
263
|
+
workshop.domains[key].status = "confirmed";
|
|
264
|
+
workshop.domains[key].user_confirmation_ref = `confirm:${key}`;
|
|
265
|
+
}
|
|
266
|
+
const exp3Raw = await harness.callTool("sf_expand", { task_id: taskId, architecture_decision_workshop: workshop });
|
|
267
|
+
const exp3 = harness.parseResult(exp3Raw);
|
|
268
|
+
const trace = await harness.collectTrace();
|
|
269
|
+
return {
|
|
270
|
+
scenario_id: "release-scenario-architecture-workshop-confirmation-block",
|
|
271
|
+
status: (exp3.status !== "awaiting_confirmation" && exp3.status !== "blocked") ? "pass" : "fail",
|
|
272
|
+
evidence: `sf_classify→sf_expand(awaiting_confirmation,workshop=true,domains=${domainKeys.length})→partial(${confirmedCount}/${domainKeys.length})→sf_expand(awaiting_confirmation)→all confirm→sf_expand(${exp3.status ?? "pass"})`,
|
|
273
|
+
production_trace: trace,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
finally {
|
|
277
|
+
harness.cleanup();
|
|
278
|
+
}
|
|
140
279
|
},
|
|
141
280
|
},
|
|
142
|
-
// 场景 4:
|
|
281
|
+
// 场景 4: 低风险不触发架构研讨
|
|
143
282
|
{
|
|
144
283
|
scenario_id: "release-scenario-architecture-workshop-low-risk-skip",
|
|
145
284
|
covering_problem: "problem-61",
|
|
146
285
|
test_files: ["tests/engine/architecture_decision_workshop.test.ts"],
|
|
147
|
-
production_entrypoint: "
|
|
148
|
-
expected_outcome: "
|
|
286
|
+
production_entrypoint: "sf_classify → sf_expand",
|
|
287
|
+
expected_outcome: "低风险修改 sf_expand 不创建 architecture_decision_workshop,不 awaiting_confirmation",
|
|
149
288
|
runner: async () => {
|
|
150
|
-
const {
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
289
|
+
const { createToolHarness } = await import("./release_tool_harness.js");
|
|
290
|
+
const harness = await createToolHarness();
|
|
291
|
+
try {
|
|
292
|
+
const clsRaw = await harness.callTool("sf_classify", { intent: "修复按钮文字拼写错误" });
|
|
293
|
+
const cls = harness.parseResult(clsRaw);
|
|
294
|
+
const taskId = cls.task_id;
|
|
295
|
+
if (!taskId)
|
|
296
|
+
return { scenario_id: "release-scenario-architecture-workshop-low-risk-skip", status: "fail", error: "sf_classify 未返回 task_id" };
|
|
297
|
+
const expRaw = await harness.callTool("sf_expand", { task_id: taskId });
|
|
298
|
+
const exp = harness.parseResult(expRaw);
|
|
299
|
+
if (exp.architecture_decision_workshop)
|
|
300
|
+
return { scenario_id: "release-scenario-architecture-workshop-low-risk-skip", status: "fail", error: "low-risk intent should not create architecture_decision_workshop" };
|
|
301
|
+
if (exp.status === "awaiting_confirmation")
|
|
302
|
+
return { scenario_id: "release-scenario-architecture-workshop-low-risk-skip", status: "fail", error: "low-risk intent should not be awaiting_confirmation" };
|
|
303
|
+
const trace = await harness.collectTrace();
|
|
304
|
+
if (trace.diagnostic_codes.length === 0) {
|
|
305
|
+
trace.diagnostic_codes = [`route:${cls.route_decision?.route ?? "unknown"}`, `expand_status:${exp.status ?? "ok"}`];
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
scenario_id: "release-scenario-architecture-workshop-low-risk-skip",
|
|
309
|
+
status: "pass",
|
|
310
|
+
evidence: `sf_classify→sf_expand(workshop=false,route=${cls.route_decision?.route},status=${exp.status}) 低风险跳过架构研讨`,
|
|
311
|
+
production_trace: trace,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
finally {
|
|
315
|
+
harness.cleanup();
|
|
316
|
+
}
|
|
163
317
|
},
|
|
164
318
|
},
|
|
165
|
-
// 场景 5: rework_required
|
|
319
|
+
// 场景 5: rework_required 域阻断设计生成
|
|
166
320
|
{
|
|
167
321
|
scenario_id: "release-scenario-architecture-workshop-rework",
|
|
168
322
|
covering_problem: "problem-61",
|
|
169
323
|
test_files: [],
|
|
170
|
-
production_entrypoint: "
|
|
171
|
-
expected_outcome: "rework_required
|
|
324
|
+
production_entrypoint: "sf_classify → sf_expand → inject rework_required → sf_expand",
|
|
325
|
+
expected_outcome: "rework_required 域仍出现在 missing/阻断中,不进入正式设计生成;修正为 confirmed 后放行",
|
|
172
326
|
runner: async () => {
|
|
173
|
-
const {
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
327
|
+
const { createToolHarness } = await import("./release_tool_harness.js");
|
|
328
|
+
const harness = await createToolHarness();
|
|
329
|
+
try {
|
|
330
|
+
const clsRaw = await harness.callTool("sf_classify", { intent: "为新系统生成架构设计文档" });
|
|
331
|
+
const cls = harness.parseResult(clsRaw);
|
|
332
|
+
const taskId = cls.task_id;
|
|
333
|
+
if (!taskId)
|
|
334
|
+
return { scenario_id: "release-scenario-architecture-workshop-rework", status: "fail", error: "sf_classify 未返回 task_id" };
|
|
335
|
+
// 提供完整技术决策契约,确保证据门禁和决策主权门禁通过
|
|
336
|
+
if (!await injectTechDecisionForWorkshop(harness, taskId))
|
|
337
|
+
return { scenario_id: "release-scenario-architecture-workshop-rework", status: "fail", error: "task context load failed" };
|
|
338
|
+
const exp1Raw = await harness.callTool("sf_expand", { task_id: taskId });
|
|
339
|
+
const exp1 = harness.parseResult(exp1Raw);
|
|
340
|
+
if (exp1.status !== "awaiting_confirmation")
|
|
341
|
+
return { scenario_id: "release-scenario-architecture-workshop-rework", status: "fail", error: `expected awaiting_confirmation, got status=${exp1.status}` };
|
|
342
|
+
const workshop = exp1.architecture_decision_workshop;
|
|
343
|
+
if (!workshop)
|
|
344
|
+
return { scenario_id: "release-scenario-architecture-workshop-rework", status: "fail", error: "sf_expand 未返回 architecture_decision_workshop" };
|
|
345
|
+
const domainKeys = Object.keys(workshop.domains ?? {});
|
|
346
|
+
// 确认大部分域,但将一个域设为 rework_required
|
|
347
|
+
const reworkKey = domainKeys.find(k => k === "backend_architecture") ?? domainKeys[0];
|
|
348
|
+
for (const key of domainKeys) {
|
|
349
|
+
if (key === reworkKey) {
|
|
350
|
+
workshop.domains[key].status = "rework_required";
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
workshop.domains[key].status = "confirmed";
|
|
354
|
+
workshop.domains[key].user_confirmation_ref = `confirm:${key}`;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
workshop.document_output_confirmation_ref = "confirm:output";
|
|
358
|
+
const exp2Raw = await harness.callTool("sf_expand", { task_id: taskId, architecture_decision_workshop: workshop });
|
|
359
|
+
const exp2 = harness.parseResult(exp2Raw);
|
|
360
|
+
if (exp2.status !== "awaiting_confirmation")
|
|
361
|
+
return { scenario_id: "release-scenario-architecture-workshop-rework", status: "fail", error: `expected still awaiting_confirmation with rework_required, got status=${exp2.status}` };
|
|
362
|
+
// 修正 rework 域为 confirmed
|
|
363
|
+
workshop.domains[reworkKey].status = "confirmed";
|
|
364
|
+
workshop.domains[reworkKey].user_confirmation_ref = `confirm:${reworkKey}`;
|
|
365
|
+
const exp3Raw = await harness.callTool("sf_expand", { task_id: taskId, architecture_decision_workshop: workshop });
|
|
366
|
+
const exp3 = harness.parseResult(exp3Raw);
|
|
367
|
+
const trace = await harness.collectTrace();
|
|
368
|
+
return {
|
|
369
|
+
scenario_id: "release-scenario-architecture-workshop-rework",
|
|
370
|
+
status: (exp3.status !== "awaiting_confirmation" && exp3.status !== "blocked") ? "pass" : "fail",
|
|
371
|
+
evidence: `sf_classify→sf_expand(awaiting_confirmation,workshop=true,domains=${domainKeys.length})→${reworkKey}=rework_required→sf_expand(awaiting_confirmation)→fix→sf_expand(${exp3.status ?? "pass"})`,
|
|
372
|
+
production_trace: trace,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
finally {
|
|
376
|
+
harness.cleanup();
|
|
377
|
+
}
|
|
185
378
|
},
|
|
186
379
|
},
|
|
187
380
|
// ── 问题六十一: 非架构通用决策研讨真实 MCP 工具链 ──
|
|
@@ -763,7 +956,7 @@ const RELEASE_ISSUE_SCENARIOS = [
|
|
|
763
956
|
scenario_id: "release-scenario-template-contract-api-field-table",
|
|
764
957
|
status: "pass",
|
|
765
958
|
evidence: `${contracts.length} contracts all have ${requiredFields.length} required fields`,
|
|
766
|
-
production_trace: { tool_entrypoint: "buildTemplateAssetContracts", diagnostic_codes: [`contracts:${contracts.length}`], gates_consumed: ["contract_gate"] },
|
|
959
|
+
production_trace: { tool_entrypoint: "buildTemplateAssetContracts", diagnostic_codes: [`contracts:${contracts.length}`], gates_consumed: ["contract_gate", "engine_contract"] },
|
|
767
960
|
};
|
|
768
961
|
},
|
|
769
962
|
},
|
|
@@ -779,11 +972,13 @@ const RELEASE_ISSUE_SCENARIOS = [
|
|
|
779
972
|
const report = auditContractCoverage(process.cwd());
|
|
780
973
|
if (report.unregistered_files.length > 0)
|
|
781
974
|
return { scenario_id: "release-scenario-template-contract-authority-binding", status: "fail", error: `unregistered: ${report.unregistered_files.join(", ")}` };
|
|
975
|
+
if (!report.consumption_evidence_verified)
|
|
976
|
+
return { scenario_id: "release-scenario-template-contract-authority-binding", status: "fail", error: `consumption evidence invalid: ${report.consumption_evidence_failures.join("; ")}` };
|
|
782
977
|
return {
|
|
783
978
|
scenario_id: "release-scenario-template-contract-authority-binding",
|
|
784
979
|
status: "pass",
|
|
785
|
-
evidence: `${report.total_contracts} contracts, 0 unregistered`,
|
|
786
|
-
production_trace: { tool_entrypoint: "auditContractCoverage", diagnostic_codes: [`total:${report.total_contracts}`, `unregistered:${report.unregistered_files.length}
|
|
980
|
+
evidence: `${report.total_contracts} contracts, 0 unregistered, consumption evidence verified`,
|
|
981
|
+
production_trace: { tool_entrypoint: "auditContractCoverage", diagnostic_codes: [`total:${report.total_contracts}`, `unregistered:${report.unregistered_files.length}`, "consumption-evidence:verified"], gates_consumed: ["contract_gate", "engine_contract"] },
|
|
787
982
|
};
|
|
788
983
|
},
|
|
789
984
|
},
|
|
@@ -808,7 +1003,7 @@ const RELEASE_ISSUE_SCENARIOS = [
|
|
|
808
1003
|
scenario_id: "release-scenario-template-contract-existing-doc-upgrade",
|
|
809
1004
|
status: "pass",
|
|
810
1005
|
evidence: `${activeCount} active, ${contracts.length - activeCount} non-active`,
|
|
811
|
-
production_trace: { tool_entrypoint: "buildTemplateAssetContracts", diagnostic_codes: [`active:${activeCount}`, `total:${contracts.length}`], gates_consumed: ["contract_gate"] },
|
|
1006
|
+
production_trace: { tool_entrypoint: "buildTemplateAssetContracts", diagnostic_codes: [`active:${activeCount}`, `total:${contracts.length}`], gates_consumed: ["contract_gate", "engine_contract"] },
|
|
812
1007
|
};
|
|
813
1008
|
},
|
|
814
1009
|
},
|
|
@@ -838,7 +1033,7 @@ const RELEASE_ISSUE_SCENARIOS = [
|
|
|
838
1033
|
scenario_id: "release-scenario-template-contract-conflict",
|
|
839
1034
|
status: "pass",
|
|
840
1035
|
evidence: `${contracts.length} contracts, 0 decision conflicts`,
|
|
841
|
-
production_trace: { tool_entrypoint: "getContractDecision", diagnostic_codes: [`contracts:${contracts.length}`, `conflicts:${conflicts}`], gates_consumed: ["contract_gate"] },
|
|
1036
|
+
production_trace: { tool_entrypoint: "getContractDecision", diagnostic_codes: [`contracts:${contracts.length}`, `conflicts:${conflicts}`], gates_consumed: ["contract_gate", "engine_contract"] },
|
|
842
1037
|
};
|
|
843
1038
|
},
|
|
844
1039
|
},
|
|
@@ -863,7 +1058,7 @@ const RELEASE_ISSUE_SCENARIOS = [
|
|
|
863
1058
|
scenario_id: "release-scenario-template-contract-draft-skip",
|
|
864
1059
|
status: "pass",
|
|
865
1060
|
evidence: `${nonActive.length} non-active, 0 leaked to syncable`,
|
|
866
|
-
production_trace: { tool_entrypoint: "getSyncableAssetPaths", diagnostic_codes: [`nonActive:${nonActive.length}`, `syncable:${syncable.size}`], gates_consumed: ["contract_gate"] },
|
|
1061
|
+
production_trace: { tool_entrypoint: "getSyncableAssetPaths", diagnostic_codes: [`nonActive:${nonActive.length}`, `syncable:${syncable.size}`], gates_consumed: ["contract_gate", "engine_contract"] },
|
|
867
1062
|
};
|
|
868
1063
|
},
|
|
869
1064
|
},
|
|
@@ -1028,7 +1223,7 @@ const RELEASE_ISSUE_SCENARIOS = [
|
|
|
1028
1223
|
scenario_id: "release-scenario-template-visibility-fresh-init",
|
|
1029
1224
|
status: "pass",
|
|
1030
1225
|
evidence: `${report.total} assets, ${report.pass} pass, 0 visibility fail`,
|
|
1031
|
-
production_trace: { tool_entrypoint: "observeAllConsumption", diagnostic_codes: [`total:${report.total}`, `pass:${report.pass}`], gates_consumed: ["contract_gate"] },
|
|
1226
|
+
production_trace: { tool_entrypoint: "observeAllConsumption", diagnostic_codes: [`total:${report.total}`, `pass:${report.pass}`], gates_consumed: ["contract_gate", "engine_contract"] },
|
|
1032
1227
|
};
|
|
1033
1228
|
},
|
|
1034
1229
|
},
|
|
@@ -1049,7 +1244,7 @@ const RELEASE_ISSUE_SCENARIOS = [
|
|
|
1049
1244
|
scenario_id: "release-scenario-template-visibility-internal-leak",
|
|
1050
1245
|
status: "pass",
|
|
1051
1246
|
evidence: "all internal_runtime denied",
|
|
1052
|
-
production_trace: { tool_entrypoint: "observeAllConsumption", diagnostic_codes: ["all_denied"], gates_consumed: ["contract_gate"] },
|
|
1247
|
+
production_trace: { tool_entrypoint: "observeAllConsumption", diagnostic_codes: ["all_denied"], gates_consumed: ["contract_gate", "engine_contract"] },
|
|
1053
1248
|
};
|
|
1054
1249
|
},
|
|
1055
1250
|
},
|
|
@@ -1075,7 +1270,7 @@ const RELEASE_ISSUE_SCENARIOS = [
|
|
|
1075
1270
|
scenario_id: "release-scenario-template-visibility-builtin-fallback",
|
|
1076
1271
|
status: "pass",
|
|
1077
1272
|
evidence: `syncable=${syncable.length} copied=${result.copied}`,
|
|
1078
|
-
production_trace: { tool_entrypoint: "copyKnowledgeToProject", diagnostic_codes: [`syncable:${syncable.length}`, `copied:${result.copied}`], gates_consumed: ["sync_templates", "init"] },
|
|
1273
|
+
production_trace: { tool_entrypoint: "copyKnowledgeToProject", diagnostic_codes: [`syncable:${syncable.length}`, `copied:${result.copied}`], gates_consumed: ["sync_templates", "init", "engine_contract"] },
|
|
1079
1274
|
};
|
|
1080
1275
|
}
|
|
1081
1276
|
finally {
|
|
@@ -1164,7 +1359,7 @@ const RELEASE_ISSUE_SCENARIOS = [
|
|
|
1164
1359
|
scenario_id: "release-scenario-template-visibility-user-visible-terms",
|
|
1165
1360
|
status: "pass",
|
|
1166
1361
|
evidence: `${userVisible.length} user_visible assets, 0 internal term violations`,
|
|
1167
|
-
production_trace: { tool_entrypoint: "buildTemplateAssetContracts", diagnostic_codes: [`userVisible:${userVisible.length}`, `violations:0`], gates_consumed: ["contract_gate"] },
|
|
1362
|
+
production_trace: { tool_entrypoint: "buildTemplateAssetContracts", diagnostic_codes: [`userVisible:${userVisible.length}`, `violations:0`], gates_consumed: ["contract_gate", "engine_contract"] },
|
|
1168
1363
|
};
|
|
1169
1364
|
},
|
|
1170
1365
|
},
|
|
@@ -1295,6 +1490,222 @@ const RELEASE_ISSUE_SCENARIOS = [
|
|
|
1295
1490
|
}
|
|
1296
1491
|
},
|
|
1297
1492
|
},
|
|
1493
|
+
// ── 问题六十八: 代码可维护性与可观测性契约 ──
|
|
1494
|
+
{
|
|
1495
|
+
scenario_id: "release-scenario-code-observability-payment-status-no-log",
|
|
1496
|
+
covering_problem: "problem-68",
|
|
1497
|
+
test_files: ["tests/engine/code_maintainability_observability_contract.test.ts"],
|
|
1498
|
+
production_entrypoint: "sf_expand → CodeObservabilityGate → sf_review → reviewMissingLogs → sf_deliver → evaluateDeliveryBlock",
|
|
1499
|
+
expected_outcome: "支付/账单状态更新缺少业务日志 → hard_fail 阻断交付",
|
|
1500
|
+
runner: async () => {
|
|
1501
|
+
const mod = await import("./code_maintainability_observability_contract.js");
|
|
1502
|
+
const findings = mod.reviewMissingLogs({
|
|
1503
|
+
"PaymentService.java": `public void refund(String orderId, BigDecimal amount) {
|
|
1504
|
+
orderRepository.save(order);
|
|
1505
|
+
paymentGateway.refund(orderId, amount);
|
|
1506
|
+
}`,
|
|
1507
|
+
});
|
|
1508
|
+
const blocked = mod.hasBlockingObservabilityFindings(findings);
|
|
1509
|
+
return {
|
|
1510
|
+
scenario_id: "release-scenario-code-observability-payment-status-no-log",
|
|
1511
|
+
status: blocked ? "pass" : "fail",
|
|
1512
|
+
evidence: blocked ? "hard_fail: 支付写操作无日志被检测到" : "未检测到支付写操作无日志",
|
|
1513
|
+
production_trace: { tool_entrypoint: "reviewMissingLogs", diagnostic_codes: [blocked ? "hard_fail" : "missed"], gates_consumed: ["sf_review", "engine_contract"] },
|
|
1514
|
+
};
|
|
1515
|
+
},
|
|
1516
|
+
},
|
|
1517
|
+
{
|
|
1518
|
+
scenario_id: "release-scenario-code-observability-permission-denied-no-log",
|
|
1519
|
+
covering_problem: "problem-68",
|
|
1520
|
+
test_files: ["tests/engine/code_maintainability_observability_contract.test.ts"],
|
|
1521
|
+
production_entrypoint: "sf_expand → CodeObservabilityGate → sf_review → reviewMissingLogs → sf_deliver → evaluateDeliveryBlock",
|
|
1522
|
+
expected_outcome: "权限拒绝无安全日志 → hard_fail 阻断",
|
|
1523
|
+
runner: async () => {
|
|
1524
|
+
const mod = await import("./code_maintainability_observability_contract.js");
|
|
1525
|
+
const findings = mod.reviewMissingLogs({
|
|
1526
|
+
"AuthController.java": `public void checkPermission(String userId, String resource) {
|
|
1527
|
+
if (!roleService.hasAccess(userId, resource)) {
|
|
1528
|
+
throw new AccessDeniedException("forbidden");
|
|
1529
|
+
}
|
|
1530
|
+
}`,
|
|
1531
|
+
});
|
|
1532
|
+
const blocked = mod.hasBlockingObservabilityFindings(findings);
|
|
1533
|
+
return {
|
|
1534
|
+
scenario_id: "release-scenario-code-observability-permission-denied-no-log",
|
|
1535
|
+
status: blocked ? "pass" : "fail",
|
|
1536
|
+
evidence: blocked ? "hard_fail: 权限拒绝无日志被检测到" : "未检测到权限拒绝无日志",
|
|
1537
|
+
production_trace: { tool_entrypoint: "reviewMissingLogs", diagnostic_codes: [blocked ? "hard_fail" : "missed"], gates_consumed: ["sf_review", "engine_contract"] },
|
|
1538
|
+
};
|
|
1539
|
+
},
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
scenario_id: "release-scenario-code-observability-catch-swallow",
|
|
1543
|
+
covering_problem: "problem-68",
|
|
1544
|
+
test_files: ["tests/engine/code_maintainability_observability_contract.test.ts"],
|
|
1545
|
+
production_entrypoint: "sf_expand → CodeObservabilityGate → sf_review → reviewMissingLogs → sf_deliver → evaluateDeliveryBlock",
|
|
1546
|
+
expected_outcome: "catch 后吞异常无日志 → hard_fail 阻断",
|
|
1547
|
+
runner: async () => {
|
|
1548
|
+
const mod = await import("./code_maintainability_observability_contract.js");
|
|
1549
|
+
const findings = mod.reviewMissingLogs({
|
|
1550
|
+
"OrderService.ts": `async processOrder(orderId: string) {
|
|
1551
|
+
try {
|
|
1552
|
+
await this.client.submit(orderId);
|
|
1553
|
+
} catch (e) {
|
|
1554
|
+
return false;
|
|
1555
|
+
}
|
|
1556
|
+
}`,
|
|
1557
|
+
});
|
|
1558
|
+
const blocked = mod.hasBlockingObservabilityFindings(findings);
|
|
1559
|
+
return {
|
|
1560
|
+
scenario_id: "release-scenario-code-observability-catch-swallow",
|
|
1561
|
+
status: blocked ? "pass" : "fail",
|
|
1562
|
+
evidence: blocked ? "hard_fail: catch 吞异常被检测到" : "未检测到 catch 吞异常",
|
|
1563
|
+
production_trace: { tool_entrypoint: "reviewMissingLogs", diagnostic_codes: [blocked ? "hard_fail" : "missed"], gates_consumed: ["sf_review", "engine_contract"] },
|
|
1564
|
+
};
|
|
1565
|
+
},
|
|
1566
|
+
},
|
|
1567
|
+
{
|
|
1568
|
+
scenario_id: "release-scenario-code-observability-sensitive-log",
|
|
1569
|
+
covering_problem: "problem-68",
|
|
1570
|
+
test_files: ["tests/engine/code_maintainability_observability_contract.test.ts"],
|
|
1571
|
+
production_entrypoint: "sf_expand → CodeObservabilityGate → sf_review → detectSensitiveLogs → sf_deliver → evaluateDeliveryBlock",
|
|
1572
|
+
expected_outcome: "日志输出 token/password/手机号全量 → hard_fail 阻断",
|
|
1573
|
+
runner: async () => {
|
|
1574
|
+
const mod = await import("./code_maintainability_observability_contract.js");
|
|
1575
|
+
const findings = mod.detectSensitiveLogs({
|
|
1576
|
+
"UserService.ts": `function login(user) {
|
|
1577
|
+
logger.info("user login", { token: "eyJhbGciOiJIUzI1NiJ9.xxxxx", password: user.password, phone: "13812345678" });
|
|
1578
|
+
}`,
|
|
1579
|
+
});
|
|
1580
|
+
const blocked = mod.hasBlockingObservabilityFindings(findings);
|
|
1581
|
+
return {
|
|
1582
|
+
scenario_id: "release-scenario-code-observability-sensitive-log",
|
|
1583
|
+
status: blocked ? "pass" : "fail",
|
|
1584
|
+
evidence: blocked ? `hard_fail: 敏感信息泄漏被检测到 (${findings.length} findings)` : "未检测到敏感信息泄漏",
|
|
1585
|
+
production_trace: { tool_entrypoint: "detectSensitiveLogs", diagnostic_codes: [blocked ? "hard_fail" : "missed"], gates_consumed: ["sf_review", "engine_contract"] },
|
|
1586
|
+
};
|
|
1587
|
+
},
|
|
1588
|
+
},
|
|
1589
|
+
{
|
|
1590
|
+
scenario_id: "release-scenario-code-observability-complex-rule-no-comment",
|
|
1591
|
+
covering_problem: "problem-68",
|
|
1592
|
+
test_files: ["tests/engine/code_maintainability_observability_contract.test.ts"],
|
|
1593
|
+
production_entrypoint: "sf_expand → CodeObservabilityGate → sf_review → reviewCommentQuality → sf_deliver",
|
|
1594
|
+
expected_outcome: "复杂金额计算无注释 → warning",
|
|
1595
|
+
runner: async () => {
|
|
1596
|
+
const mod = await import("./code_maintainability_observability_contract.js");
|
|
1597
|
+
const findings = mod.reviewCommentQuality({
|
|
1598
|
+
"BillingService.java": `// 金额计算逻辑
|
|
1599
|
+
public BigDecimal calculateSubsidy(Order order) {
|
|
1600
|
+
BigDecimal base = order.getAmount().multiply(new BigDecimal("0.8"));
|
|
1601
|
+
BigDecimal discount = base.subtract(order.getDeducted());
|
|
1602
|
+
return discount.max(BigDecimal.ZERO);
|
|
1603
|
+
}`,
|
|
1604
|
+
});
|
|
1605
|
+
const hasCommentWarning = findings.some(f => f.category === "missing_comment_complex");
|
|
1606
|
+
// 上面有注释不会触发缺失检测;下面测试无注释的负例:
|
|
1607
|
+
const findingsNoComment = mod.reviewCommentQuality({
|
|
1608
|
+
"金额计算/BillingService.java": `public BigDecimal calculateSubsidy(Order order) {
|
|
1609
|
+
BigDecimal base = order.getAmount().multiply(new BigDecimal("0.8"));
|
|
1610
|
+
BigDecimal discount = base.subtract(order.getDeducted());
|
|
1611
|
+
return discount.max(BigDecimal.ZERO);
|
|
1612
|
+
}`,
|
|
1613
|
+
});
|
|
1614
|
+
const detected = findingsNoComment.some(f => f.category === "missing_comment_complex");
|
|
1615
|
+
return {
|
|
1616
|
+
scenario_id: "release-scenario-code-observability-complex-rule-no-comment",
|
|
1617
|
+
status: detected ? "pass" : "fail",
|
|
1618
|
+
evidence: detected ? "warning: 无注释复杂逻辑被检测到" : "未检测到无注释复杂逻辑",
|
|
1619
|
+
production_trace: { tool_entrypoint: "reviewCommentQuality", diagnostic_codes: [detected ? "warning" : "missed"], gates_consumed: ["sf_review", "engine_contract"] },
|
|
1620
|
+
};
|
|
1621
|
+
},
|
|
1622
|
+
},
|
|
1623
|
+
{
|
|
1624
|
+
scenario_id: "release-scenario-code-observability-low-risk-skip",
|
|
1625
|
+
covering_problem: "problem-68",
|
|
1626
|
+
test_files: ["tests/engine/code_maintainability_observability_contract.test.ts"],
|
|
1627
|
+
production_entrypoint: "sf_classify → sf_expand (低风险) → 不触发可观测性门禁",
|
|
1628
|
+
expected_outcome: "简单文案修改不触发代码可维护性/可观测性契约",
|
|
1629
|
+
runner: async () => {
|
|
1630
|
+
const { createToolHarness } = await import("./release_tool_harness.js");
|
|
1631
|
+
const harness = await createToolHarness();
|
|
1632
|
+
try {
|
|
1633
|
+
const intent = "修复 README 文案错别字";
|
|
1634
|
+
const clsRaw = await harness.callTool("sf_classify", { intent });
|
|
1635
|
+
const cls = harness.parseResult(clsRaw);
|
|
1636
|
+
const taskId = cls.task_id;
|
|
1637
|
+
if (!taskId)
|
|
1638
|
+
return { scenario_id: "release-scenario-code-observability-low-risk-skip", status: "fail", error: "sf_classify 未返回 task_id" };
|
|
1639
|
+
const expRaw = await harness.callTool("sf_expand", { task_id: taskId });
|
|
1640
|
+
const exp = harness.parseResult(expRaw);
|
|
1641
|
+
// 低风险任务不应触发 SF-OBS-6801 诊断码
|
|
1642
|
+
const notBlocked = exp.diagnostic_code !== "SF-OBS-6801";
|
|
1643
|
+
return {
|
|
1644
|
+
scenario_id: "release-scenario-code-observability-low-risk-skip",
|
|
1645
|
+
status: notBlocked ? "pass" : "fail",
|
|
1646
|
+
evidence: notBlocked ? "低风险任务正确跳过可观测性门禁" : "低风险任务被错误触发可观测性门禁",
|
|
1647
|
+
production_trace: { tool_entrypoint: "sf_classify+sf_expand", diagnostic_codes: [exp.status ?? "ok", exp.diagnostic_code ?? "none"], gates_consumed: ["sf_classify", "sf_expand"] },
|
|
1648
|
+
};
|
|
1649
|
+
}
|
|
1650
|
+
catch (e) {
|
|
1651
|
+
return { scenario_id: "release-scenario-code-observability-low-risk-skip", status: "fail", error: e.message };
|
|
1652
|
+
}
|
|
1653
|
+
finally {
|
|
1654
|
+
await harness.cleanup();
|
|
1655
|
+
}
|
|
1656
|
+
},
|
|
1657
|
+
},
|
|
1658
|
+
{
|
|
1659
|
+
scenario_id: "release-scenario-code-observability-project-logger-detected",
|
|
1660
|
+
covering_problem: "problem-68",
|
|
1661
|
+
test_files: ["tests/engine/code_maintainability_observability_contract.test.ts"],
|
|
1662
|
+
production_entrypoint: "sf_expand → CodeObservabilityGate → detectProjectLogger",
|
|
1663
|
+
expected_outcome: "Java/Spring/Node/NestJS 项目能正确检测 logger 类型",
|
|
1664
|
+
runner: async () => {
|
|
1665
|
+
const mod = await import("./code_maintainability_observability_contract.js");
|
|
1666
|
+
const javaLogger = mod.detectProjectLogger({
|
|
1667
|
+
"Application.java": "import org.slf4j.LoggerFactory; private static final Logger log = LoggerFactory.getLogger(App.class);",
|
|
1668
|
+
});
|
|
1669
|
+
const pinoLogger = mod.detectProjectLogger({
|
|
1670
|
+
"index.ts": "import pino from 'pino'; const logger = pino();",
|
|
1671
|
+
});
|
|
1672
|
+
const nestjsLogger = mod.detectProjectLogger({
|
|
1673
|
+
"app.service.ts": "import { Logger } from '@nestjs/common';",
|
|
1674
|
+
});
|
|
1675
|
+
const ok = javaLogger.type === "slf4j" && pinoLogger.type === "pino" && nestjsLogger.type === "nestjs_logger";
|
|
1676
|
+
return {
|
|
1677
|
+
scenario_id: "release-scenario-code-observability-project-logger-detected",
|
|
1678
|
+
status: ok ? "pass" : "fail",
|
|
1679
|
+
evidence: ok ? `检测: ${javaLogger.type}, ${pinoLogger.type}, ${nestjsLogger.type}` : `检测失败: ${javaLogger.type}, ${pinoLogger.type}, ${nestjsLogger.type}`,
|
|
1680
|
+
production_trace: { tool_entrypoint: "detectProjectLogger", diagnostic_codes: [javaLogger.type, pinoLogger.type, nestjsLogger.type], gates_consumed: ["sf_expand", "engine_contract"] },
|
|
1681
|
+
};
|
|
1682
|
+
},
|
|
1683
|
+
},
|
|
1684
|
+
{
|
|
1685
|
+
scenario_id: "release-scenario-code-observability-migration-audit-log",
|
|
1686
|
+
covering_problem: "problem-68",
|
|
1687
|
+
test_files: ["tests/engine/code_maintainability_observability_contract.test.ts"],
|
|
1688
|
+
production_entrypoint: "sf_expand → CodeObservabilityGate → sf_review → reviewMissingLogs → sf_deliver",
|
|
1689
|
+
expected_outcome: "迁移脚本/数据修复无审计日志 → hard_fail",
|
|
1690
|
+
runner: async () => {
|
|
1691
|
+
const mod = await import("./code_maintainability_observability_contract.js");
|
|
1692
|
+
const findings = mod.reviewMissingLogs({
|
|
1693
|
+
"scripts/data_fix_order_status.ts": `async function migrateOrderStatus() {
|
|
1694
|
+
const orders = await db.query("SELECT * FROM orders WHERE status IS NULL");
|
|
1695
|
+
for (const order of orders) {
|
|
1696
|
+
await db.update("UPDATE orders SET status = 'pending' WHERE id = ?", [order.id]);
|
|
1697
|
+
}
|
|
1698
|
+
}`,
|
|
1699
|
+
});
|
|
1700
|
+
const blocked = mod.hasBlockingObservabilityFindings(findings);
|
|
1701
|
+
return {
|
|
1702
|
+
scenario_id: "release-scenario-code-observability-migration-audit-log",
|
|
1703
|
+
status: blocked ? "pass" : "fail",
|
|
1704
|
+
evidence: blocked ? "hard_fail: 迁移脚本无审计日志被检测到" : "未检测到迁移脚本无审计日志",
|
|
1705
|
+
production_trace: { tool_entrypoint: "reviewMissingLogs", diagnostic_codes: [blocked ? "hard_fail" : "missed"], gates_consumed: ["sf_review", "engine_contract"] },
|
|
1706
|
+
};
|
|
1707
|
+
},
|
|
1708
|
+
},
|
|
1298
1709
|
];
|
|
1299
1710
|
/** 获取全量场景定义 */
|
|
1300
1711
|
export function getReleaseIssueScenarios() {
|