soloforge 1.3.9 → 1.4.0
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 +10 -0
- package/dist/adapters/claude_code/hooks.d.ts.map +1 -1
- package/dist/adapters/claude_code/hooks.js +9 -0
- package/dist/adapters/claude_code/hooks.js.map +1 -1
- package/dist/adapters/claude_code/tools.d.ts.map +1 -1
- package/dist/adapters/claude_code/tools.js +44 -3
- package/dist/adapters/claude_code/tools.js.map +1 -1
- package/dist/adapters/codex/codex_config.d.ts.map +1 -1
- package/dist/adapters/codex/codex_config.js +10 -0
- package/dist/adapters/codex/codex_config.js.map +1 -1
- package/dist/bin/soloforge.d.ts.map +1 -1
- package/dist/bin/soloforge.js +154 -0
- package/dist/bin/soloforge.js.map +1 -1
- package/dist/engine/control_plane_contract.d.ts +59 -0
- package/dist/engine/control_plane_contract.d.ts.map +1 -0
- package/dist/engine/control_plane_contract.js +246 -0
- package/dist/engine/control_plane_contract.js.map +1 -0
- package/dist/engine/historical_issue_mechanization_matrix.js +7 -7
- package/dist/engine/historical_issue_mechanization_matrix.js.map +1 -1
- package/dist/engine/implementation_roadmap_registry.d.ts.map +1 -1
- package/dist/engine/implementation_roadmap_registry.js +45 -1
- package/dist/engine/implementation_roadmap_registry.js.map +1 -1
- package/dist/engine/release_readiness_gate.d.ts +1 -0
- package/dist/engine/release_readiness_gate.d.ts.map +1 -1
- package/dist/engine/release_readiness_gate.js +95 -4
- package/dist/engine/release_readiness_gate.js.map +1 -1
- package/dist/engine/tool_invocation_contract_registry.js +17 -17
- package/dist/engine/tool_invocation_contract_registry.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release_readiness_gate.d.ts","sourceRoot":"","sources":["../../src/engine/release_readiness_gate.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"release_readiness_gate.d.ts","sourceRoot":"","sources":["../../src/engine/release_readiness_gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAQH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,uBAAuB,EAAE,CAAC;IACtC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACpD,eAAe,EAAE,MAAM,CAAC;CACzB;AAwwHD,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAmK9F"}
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
* 19. 历史问题长期机制化行为验证
|
|
26
26
|
* 20. 诊断码集中治理检查
|
|
27
27
|
* 21. 模板卫生与项目知识消费验证
|
|
28
|
+
* 22. MCP 控制面可信与受控生成链路验证
|
|
28
29
|
*/
|
|
29
30
|
import fs from "node:fs";
|
|
30
31
|
import os from "node:os";
|
|
@@ -1147,14 +1148,14 @@ async function checkBatchIssueFormatConsistency(rootDir, hardFail, _info) {
|
|
|
1147
1148
|
hardFail("BATCH_ISSUE_FORMAT_INCONSISTENT", "共享解析脚本缺少 Batch 加载或 canonical ledger 校验导出", ["scripts/batch_issue_details.mjs"], "构建系统", "共享解析脚本导出不正确", "修复脚本");
|
|
1148
1149
|
return;
|
|
1149
1150
|
}
|
|
1150
|
-
const expectedCounts = { 1: 19, 2: 12, 3: 9, 4: 14, 5: 6, 6: 5, 7: 2, 8: 4 };
|
|
1151
|
+
const expectedCounts = { 1: 19, 2: 12, 3: 9, 4: 14, 5: 6, 6: 5, 7: 2, 8: 4, 9: 1 };
|
|
1151
1152
|
const parsedBatches = [];
|
|
1152
1153
|
const requiredPerProblemSections = [
|
|
1153
1154
|
"问题背景", "用户反馈 / 触发场景", "根因分析", "解决方案", "方案细节",
|
|
1154
1155
|
"硬规则", "非目标", "影响范围", "落地文件", "验收标准", "回归风险",
|
|
1155
1156
|
"与其他问题的关联", "发布门禁要求",
|
|
1156
1157
|
];
|
|
1157
|
-
for (let batch = 1; batch <=
|
|
1158
|
+
for (let batch = 1; batch <= 9; batch++) {
|
|
1158
1159
|
const details = loadBatchIssueDetails(batch, rootDir);
|
|
1159
1160
|
parsedBatches.push(details);
|
|
1160
1161
|
if (!details.loaded) {
|
|
@@ -1204,7 +1205,7 @@ async function checkBatchIssueFormatConsistency(rootDir, hardFail, _info) {
|
|
|
1204
1205
|
const roadmapPath = path.join(rootDir, "dist", "engine", "implementation_roadmap_registry.js");
|
|
1205
1206
|
const roadmap = await import(roadmapPath);
|
|
1206
1207
|
const roadmapProblems = roadmap.listAllProblems();
|
|
1207
|
-
const ledgerFindings = validateCanonicalIssueLedger(parsedBatches, roadmapProblems,
|
|
1208
|
+
const ledgerFindings = validateCanonicalIssueLedger(parsedBatches, roadmapProblems, 72);
|
|
1208
1209
|
for (const finding of ledgerFindings) {
|
|
1209
1210
|
hardFail("CANONICAL_ISSUE_LEDGER_INCONSISTENT", finding.message, ["scripts/batch_issue_details.mjs", "src/engine/implementation_roadmap_registry.ts"], finding.issue_label ?? finding.problem_id ?? "canonical-ledger", "旧 gate 只校验单份文档格式与数量,不校验 Batch 文档和 roadmap 的唯一身份映射", "修正 canonical issue ID、文档归属或 roadmap 登记");
|
|
1210
1211
|
}
|
|
@@ -1214,7 +1215,7 @@ async function checkBatchIssueFormatConsistency(rootDir, hardFail, _info) {
|
|
|
1214
1215
|
hardFail("CANONICAL_ISSUE_LEDGER_INCONSISTENT", finding.message, ["src/engine/implementation_roadmap_registry.ts"], finding.subject_id ?? "roadmap", "旧 gate 不执行 roadmap 内部双向引用校验", "修正 ProblemEntry 与 ImplementationBatch 的双向归属");
|
|
1215
1216
|
}
|
|
1216
1217
|
if (ledgerFindings.length === 0 && roadmapFindings.length === 0) {
|
|
1217
|
-
_info(" canonical ledger: 问题文档与 roadmap 的
|
|
1218
|
+
_info(" canonical ledger: 问题文档与 roadmap 的 72 个问题身份、归属一致");
|
|
1218
1219
|
}
|
|
1219
1220
|
}
|
|
1220
1221
|
catch (e) {
|
|
@@ -2930,6 +2931,92 @@ async function checkDiagnosticCentralization(rootDir, hardFail) {
|
|
|
2930
2931
|
hardFail("DIAGNOSTIC_CODE_REGISTRY_MISSING", `诊断码常量未在注册表登记: ${missing.join(", ")}`, ["src/engine/diagnostic_registry.ts"], "problem-36", "旧 gate 不检查诊断码注册完整性", "补齐 BUILTIN_DIAGNOSTICS");
|
|
2931
2932
|
}
|
|
2932
2933
|
}
|
|
2934
|
+
async function checkControlPlaneTrustBehavior(rootDir, hardFail) {
|
|
2935
|
+
try {
|
|
2936
|
+
const control = await import("./control_plane_contract.js");
|
|
2937
|
+
const toolContracts = await import("./tool_invocation_contract_registry.js");
|
|
2938
|
+
const matrix = control.CONTROL_PLANE_MATRIX ?? [];
|
|
2939
|
+
const branchDetails = control.CONTROL_PLANE_BRANCH_DETAILS ?? [];
|
|
2940
|
+
if (matrix.length !== 15) {
|
|
2941
|
+
hardFail("CONTROL_PLANE_MATRIX_INCOMPLETE", `控制面矩阵数量应为 15,实际为 ${matrix.length}`, ["src/engine/control_plane_contract.ts"], "problem-72", "旧 gate 不覆盖 MCP 控制面可用性与旁路", "补齐控制面矩阵");
|
|
2942
|
+
}
|
|
2943
|
+
if (branchDetails.length < 30) {
|
|
2944
|
+
hardFail("CONTROL_PLANE_BRANCH_DETAILS_INCOMPLETE", `控制面枝叶细节至少 30 条,实际为 ${branchDetails.length}`, ["src/engine/control_plane_contract.ts"], "problem-72", "旧 gate 不覆盖枝叶防回归细节", "补齐枝叶细节");
|
|
2945
|
+
}
|
|
2946
|
+
if (!control.isSoloforgeStateBypassCommand("rm -rf .soloforge/state/current-task.json")) {
|
|
2947
|
+
hardFail("CONTROL_PLANE_BYPASS_GUARD_FALSE_NEGATIVE", "Bash 直接删除 .soloforge/state 未被识别为旁路", ["src/engine/control_plane_contract.ts", "src/bin/soloforge.ts"], "problem-72", "旧 gate 不验证 Bash/Edit/Write 旁路", "修复旁路拦截");
|
|
2948
|
+
}
|
|
2949
|
+
if (control.isSoloforgeStateBypassCommand("cat .soloforge/state/current-task.json")) {
|
|
2950
|
+
hardFail("CONTROL_PLANE_BYPASS_GUARD_FALSE_POSITIVE", "只读查看 .soloforge/state 被误判为写旁路", ["src/engine/control_plane_contract.ts"], "problem-72", "旧 gate 不检查旁路误拦", "修复旁路判断");
|
|
2951
|
+
}
|
|
2952
|
+
const contractFindings = control.validateControlPlaneToolContracts(toolContracts.listToolInvocationContracts());
|
|
2953
|
+
const hardContractFindings = contractFindings.filter((finding) => finding.severity === "hard_fail");
|
|
2954
|
+
if (hardContractFindings.length > 0) {
|
|
2955
|
+
hardFail("CONTROL_PLANE_TOOL_CONTRACT_INVALID", `工具控制面契约存在 ${hardContractFindings.length} 个 hard_fail: ${hardContractFindings.map((f) => f.code).join(", ")}`, ["src/engine/tool_invocation_contract_registry.ts"], "problem-72", "旧 gate 不检查工具错标和死链路", "修复工具契约");
|
|
2956
|
+
}
|
|
2957
|
+
const fakeContractFindings = control.validateControlPlaneToolContracts([{
|
|
2958
|
+
tool_name: "sf_fake_readonly_writer",
|
|
2959
|
+
category: "read_only_bypass",
|
|
2960
|
+
side_effects: ["task_context_write"],
|
|
2961
|
+
requires_authorization: false,
|
|
2962
|
+
requires_workflow: false,
|
|
2963
|
+
description: "错误契约",
|
|
2964
|
+
default_next_tools: [],
|
|
2965
|
+
forbidden_next_tools: [],
|
|
2966
|
+
}]);
|
|
2967
|
+
if (!fakeContractFindings.some((finding) => finding.code === "CONTROL_PLANE_READ_ONLY_HAS_SIDE_EFFECT")) {
|
|
2968
|
+
hardFail("CONTROL_PLANE_TOOL_CONTRACT_FALSE_PASS", "read_only_bypass 写状态的假契约未被阻断", ["src/engine/control_plane_contract.ts"], "problem-72", "旧 gate 不验证契约错标 must-fail", "修复工具契约验证");
|
|
2969
|
+
}
|
|
2970
|
+
const bypassAssessment = control.assessControlledGenerationChain({
|
|
2971
|
+
changed_files: ["src/Foo.java"],
|
|
2972
|
+
verified_files: ["src/Foo.java"],
|
|
2973
|
+
traces: [{ tool_name: "Bash", status: "passed", evidence_kind: "command_execution" }],
|
|
2974
|
+
delivery_status: "delivered",
|
|
2975
|
+
});
|
|
2976
|
+
if (bypassAssessment.accepted || !bypassAssessment.findings.some((finding) => finding.code === "CONTROLLED_GENERATION_MISSING_MCP_PROVENANCE")) {
|
|
2977
|
+
hardFail("CONTROLLED_GENERATION_BYPASS_FALSE_PASS", "非 MCP 生成代码被错误接受为完整可信交付", ["src/engine/control_plane_contract.ts"], "problem-72", "旧 gate 不验证来源归因", "修复受控生成链路");
|
|
2978
|
+
}
|
|
2979
|
+
const partialAssessment = control.assessControlledGenerationChain({
|
|
2980
|
+
changed_files: ["src/Foo.java", "src/Bar.java"],
|
|
2981
|
+
verified_files: ["src/Foo.java"],
|
|
2982
|
+
traces: [
|
|
2983
|
+
{ tool_name: "sf_classify", task_id: "t1", status: "passed" },
|
|
2984
|
+
{ tool_name: "sf_expand", task_id: "t1", status: "passed" },
|
|
2985
|
+
{ tool_name: "sf_verify", task_id: "t1", status: "passed", evidence_kind: "command_execution" },
|
|
2986
|
+
],
|
|
2987
|
+
delivery_status: "delivered",
|
|
2988
|
+
});
|
|
2989
|
+
if (partialAssessment.accepted || !partialAssessment.findings.some((finding) => finding.code === "CONTROLLED_GENERATION_CHANGED_FILE_UNVERIFIED")) {
|
|
2990
|
+
hardFail("CONTROLLED_GENERATION_SCOPE_FALSE_PASS", "changed_files 子集验证被错误接受", ["src/engine/control_plane_contract.ts"], "problem-72", "旧 gate 不验证范围完整性", "修复验证范围对账");
|
|
2991
|
+
}
|
|
2992
|
+
const passAssessment = control.assessControlledGenerationChain({
|
|
2993
|
+
changed_files: ["src/Foo.java"],
|
|
2994
|
+
verified_files: ["src/Foo.java"],
|
|
2995
|
+
traces: [
|
|
2996
|
+
{ tool_name: "sf_classify", task_id: "t1", status: "passed" },
|
|
2997
|
+
{ tool_name: "sf_expand", task_id: "t1", status: "passed" },
|
|
2998
|
+
{ tool_name: "sf_verify", task_id: "t1", status: "passed", evidence_kind: "command_execution" },
|
|
2999
|
+
{ tool_name: "sf_deliver", task_id: "t1", status: "passed" },
|
|
3000
|
+
],
|
|
3001
|
+
delivery_status: "delivered",
|
|
3002
|
+
});
|
|
3003
|
+
if (!passAssessment.accepted || passAssessment.confidence !== "full") {
|
|
3004
|
+
hardFail("CONTROLLED_GENERATION_VALID_CHAIN_BLOCKED", "完整 MCP 受控生成链路被误阻断", ["src/engine/control_plane_contract.ts"], "problem-72", "旧 gate 不验证 must-pass", "修复受控生成链路");
|
|
3005
|
+
}
|
|
3006
|
+
const cliText = safeRead(path.join(rootDir, "src", "bin", "soloforge.ts")) ?? "";
|
|
3007
|
+
if (!cliText.includes("case \"doctor\"") || !cliText.includes("auditControlPlaneProject")) {
|
|
3008
|
+
hardFail("CONTROL_PLANE_DOCTOR_MISSING", "CLI 未提供 soloforge doctor 控制面诊断入口", ["src/bin/soloforge.ts"], "problem-72", "旧 gate 没有 MCP 控制面恢复入口", "补 soloforge doctor");
|
|
3009
|
+
}
|
|
3010
|
+
if (!cliText.includes("仍处于 ${currentTask.status}") ||
|
|
3011
|
+
!cliText.includes("缺少 design_artifact_pack") ||
|
|
3012
|
+
!cliText.includes("没有受控 SoloForge 任务")) {
|
|
3013
|
+
hardFail("CONTROLLED_IMPLEMENTATION_WRITE_GATE_MISSING", "check-write 未覆盖 expanding 卡死、设计产物存在但缺 design_artifact_pack、无受控任务三类直接编码旁路", ["src/bin/soloforge.ts"], "problem-72", "旧 gate 只在交付层发现非 MCP 来源,未在写入入口阻断真实用户项目旁路", "在 check-write 对业务实现文件增加受控任务与设计产物包前置门");
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
catch (e) {
|
|
3017
|
+
hardFail("CONTROL_PLANE_BEHAVIOR_EXCEPTION", `控制面可信行为验证异常: ${e.message}`, ["src/engine/control_plane_contract.ts"], "problem-72", "旧 gate 不验证控制面可信", "修复控制面契约模块");
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
2933
3020
|
// ── 主入口 ──
|
|
2934
3021
|
export async function runReleaseReadinessGate(rootDir) {
|
|
2935
3022
|
const hardFails = [];
|
|
@@ -3044,6 +3131,10 @@ export async function runReleaseReadinessGate(rootDir) {
|
|
|
3044
3131
|
beginPhase("模板卫生与项目知识消费验证");
|
|
3045
3132
|
await checkTemplateAndProjectKnowledgeHygiene(rootDir, hardFail, _info);
|
|
3046
3133
|
endPhase("模板卫生与项目知识消费验证");
|
|
3134
|
+
// 22: MCP 控制面可信与受控生成链路验证
|
|
3135
|
+
beginPhase("MCP 控制面可信与受控生成链路验证");
|
|
3136
|
+
await checkControlPlaneTrustBehavior(rootDir, hardFail);
|
|
3137
|
+
endPhase("MCP 控制面可信与受控生成链路验证");
|
|
3047
3138
|
// 恢复 console.error 和日志器
|
|
3048
3139
|
console.error = origConsoleError;
|
|
3049
3140
|
resetLogger();
|