soloforge 1.1.72 → 1.1.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/types.d.ts +11 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/domain/asset_registry/derived_types.d.ts +1 -1
- package/dist/domain/asset_registry/derived_types.d.ts.map +1 -1
- package/dist/gate/contracts/deviation_metrics.d.ts +42 -0
- package/dist/gate/contracts/deviation_metrics.d.ts.map +1 -0
- package/dist/gate/contracts/deviation_metrics.js +40 -0
- package/dist/gate/contracts/deviation_metrics.js.map +1 -0
- package/dist/gate/executors/executors_arch_conduction.d.ts +2 -0
- package/dist/gate/executors/executors_arch_conduction.d.ts.map +1 -0
- package/dist/gate/executors/executors_arch_conduction.js +58 -0
- package/dist/gate/executors/executors_arch_conduction.js.map +1 -0
- package/dist/gate/executors/executors_arch_coverage.d.ts +2 -0
- package/dist/gate/executors/executors_arch_coverage.d.ts.map +1 -0
- package/dist/gate/executors/executors_arch_coverage.js +67 -0
- package/dist/gate/executors/executors_arch_coverage.js.map +1 -0
- package/dist/gate/executors/executors_companion.d.ts +2 -0
- package/dist/gate/executors/executors_companion.d.ts.map +1 -0
- package/dist/gate/executors/executors_companion.js +74 -0
- package/dist/gate/executors/executors_companion.js.map +1 -0
- package/dist/gate/executors/executors_crud.d.ts +4 -0
- package/dist/gate/executors/executors_crud.d.ts.map +1 -0
- package/dist/gate/executors/executors_crud.js +130 -0
- package/dist/gate/executors/executors_crud.js.map +1 -0
- package/dist/gate/executors/executors_deviation_summary.d.ts +2 -0
- package/dist/gate/executors/executors_deviation_summary.d.ts.map +1 -0
- package/dist/gate/executors/executors_deviation_summary.js +56 -0
- package/dist/gate/executors/executors_deviation_summary.js.map +1 -0
- package/dist/gate/executors/executors_field_mapping.d.ts.map +1 -1
- package/dist/gate/executors/executors_field_mapping.js +3 -2
- package/dist/gate/executors/executors_field_mapping.js.map +1 -1
- package/dist/gate/executors/executors_openapi_conformance.d.ts +6 -0
- package/dist/gate/executors/executors_openapi_conformance.d.ts.map +1 -0
- package/dist/gate/executors/executors_openapi_conformance.js +119 -0
- package/dist/gate/executors/executors_openapi_conformance.js.map +1 -0
- package/dist/gate/executors/executors_proto_interaction.d.ts +2 -0
- package/dist/gate/executors/executors_proto_interaction.d.ts.map +1 -0
- package/dist/gate/executors/executors_proto_interaction.js +65 -0
- package/dist/gate/executors/executors_proto_interaction.js.map +1 -0
- package/dist/gate/executors/executors_required_artifact.d.ts +2 -0
- package/dist/gate/executors/executors_required_artifact.d.ts.map +1 -0
- package/dist/gate/executors/executors_required_artifact.js +49 -0
- package/dist/gate/executors/executors_required_artifact.js.map +1 -0
- package/dist/gate/executors/executors_schema_conformance.d.ts +4 -0
- package/dist/gate/executors/executors_schema_conformance.d.ts.map +1 -0
- package/dist/gate/executors/executors_schema_conformance.js +91 -0
- package/dist/gate/executors/executors_schema_conformance.js.map +1 -0
- package/dist/gate/executors/executors_section_integrity.d.ts +2 -0
- package/dist/gate/executors/executors_section_integrity.d.ts.map +1 -0
- package/dist/gate/executors/executors_section_integrity.js +95 -0
- package/dist/gate/executors/executors_section_integrity.js.map +1 -0
- package/dist/gate/executors/executors_slice_contract.d.ts +4 -0
- package/dist/gate/executors/executors_slice_contract.d.ts.map +1 -0
- package/dist/gate/executors/executors_slice_contract.js +62 -0
- package/dist/gate/executors/executors_slice_contract.js.map +1 -0
- package/dist/gate/executors/index.d.ts.map +1 -1
- package/dist/gate/executors/index.js +22 -0
- package/dist/gate/executors/index.js.map +1 -1
- package/dist/gate/gate_engine.d.ts +7 -0
- package/dist/gate/gate_engine.d.ts.map +1 -1
- package/dist/gate/gate_engine.js.map +1 -1
- package/dist/server/tools/sf_work.d.ts.map +1 -1
- package/dist/server/tools/sf_work.js +3 -0
- package/dist/server/tools/sf_work.js.map +1 -1
- package/package.json +1 -1
- package/templates/build/enforced.md +24 -0
- package/templates/design/enforced.md +54 -0
- package/templates/design//346/236/266/346/236/204/350/256/276/350/256/241/346/226/207/346/241/243.md +8 -0
- package/templates/shared/deterministic_executors.json +11 -0
- package/templates/verify/enforced.md +15 -0
- package/templates/verify//344/272/244/344/273/230/345/256/214/345/244/207/346/200/247/345/256/241/346/237/245.md +1 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 交付偏差汇总执行器 — 读 .soloforge/gates/ 各 gate 的 check_results,调 summarizeDeviation 汇总四维偏差率。
|
|
3
|
+
* 输出「交付偏差 = X%」,gate 阈值 ≤5%(从 rule 提取)。
|
|
4
|
+
*
|
|
5
|
+
* 被谁调用:gate_engine(deviation_summary executor,挂 verify-gate 汇总 design+build+verify)
|
|
6
|
+
* 数据流:.soloforge/gates/*.json 的 check_results[].metric → summarizeDeviation → 偏差率 → CheckResult
|
|
7
|
+
*/
|
|
8
|
+
import { gateExecutors } from "../gate_executors.js";
|
|
9
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { summarizeDeviation } from "../contracts/deviation_metrics.js";
|
|
12
|
+
export function registerDeviationSummaryExecutor() {
|
|
13
|
+
gateExecutors.register("deviation_summary", async (check, ctx) => {
|
|
14
|
+
try {
|
|
15
|
+
const gatesDir = join(ctx.projectRoot, ".soloforge", "gates");
|
|
16
|
+
if (!existsSync(gatesDir)) {
|
|
17
|
+
return { check_id: check.id, executed_by: "code", passed: true, skipped: true,
|
|
18
|
+
evidence: "无 gate 记录(.soloforge/gates/),跳过偏差汇总",
|
|
19
|
+
metric: { passed: 0, total: 0, deviation_rate: 0 } };
|
|
20
|
+
}
|
|
21
|
+
const allResults = [];
|
|
22
|
+
for (const f of readdirSync(gatesDir)) {
|
|
23
|
+
if (!f.endsWith(".json"))
|
|
24
|
+
continue;
|
|
25
|
+
try {
|
|
26
|
+
const rec = JSON.parse(readFileSync(join(gatesDir, f), "utf-8"));
|
|
27
|
+
if (Array.isArray(rec.check_results))
|
|
28
|
+
allResults.push(...rec.check_results);
|
|
29
|
+
}
|
|
30
|
+
catch { /* skip corrupt */ }
|
|
31
|
+
}
|
|
32
|
+
if (allResults.length === 0) {
|
|
33
|
+
return { check_id: check.id, executed_by: "code", passed: true, skipped: true,
|
|
34
|
+
evidence: "gate 记录无 check_results,跳过", metric: { passed: 0, total: 0, deviation_rate: 0 } };
|
|
35
|
+
}
|
|
36
|
+
const summary = summarizeDeviation(allResults);
|
|
37
|
+
const thresholdMatch = check.rule?.match(/(\d+(?:\.\d+)?)\s*%/);
|
|
38
|
+
const threshold = thresholdMatch ? parseFloat(thresholdMatch[1]) / 100 : 0.05;
|
|
39
|
+
const pct = summary.total_deviation * 100;
|
|
40
|
+
const passed = summary.total_deviation <= threshold;
|
|
41
|
+
const dimStr = Object.entries(summary.dimensions)
|
|
42
|
+
.map(([k, v]) => `${k}=${(v.rate * 100).toFixed(0)}%`).join(",");
|
|
43
|
+
return {
|
|
44
|
+
check_id: check.id, executed_by: "code", passed,
|
|
45
|
+
metric: { passed: Math.round((1 - summary.total_deviation) * 100), total: 100, deviation_rate: summary.total_deviation },
|
|
46
|
+
evidence: `交付偏差 = ${pct.toFixed(1)}%(阈值 ${(threshold * 100).toFixed(1)}%);维度[${dimStr}];采样 ${summary.sampled_checks} check`,
|
|
47
|
+
error: passed ? undefined : `交付偏差 ${pct.toFixed(1)}% > 阈值 ${(threshold * 100).toFixed(1)}%(确定性偏差未清零;语义偏差另需 AI/人工/E2E)`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
return { check_id: check.id, executed_by: "code", passed: false,
|
|
52
|
+
error: `deviation_summary 执行异常(fail-closed):${err instanceof Error ? err.message : String(err)}` };
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=executors_deviation_summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executors_deviation_summary.js","sourceRoot":"","sources":["../../../src/gate/executors/executors_deviation_summary.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executors_field_mapping.d.ts","sourceRoot":"","sources":["../../../src/gate/executors/executors_field_mapping.ts"],"names":[],"mappings":"AAiEA,oDAAoD;AACpD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"executors_field_mapping.d.ts","sourceRoot":"","sources":["../../../src/gate/executors/executors_field_mapping.ts"],"names":[],"mappings":"AAiEA,oDAAoD;AACpD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAwB9E;AAED;;;;mCAImC;AACnC,wBAAgB,4BAA4B,IAAI,IAAI,CAgGnD"}
|
|
@@ -69,8 +69,9 @@ export function parseSchemaSqlTables(content) {
|
|
|
69
69
|
const fields = new Map();
|
|
70
70
|
// CREATE TABLE `表` (字段 VARCHAR(128), ...) ENGINE=InnoDB... / COMMENT='表注释' / ; —— body 到“表的 ) 后跟表选项或 ;”
|
|
71
71
|
// 用 )\s*(?:ENGINE|DEFAULT|CHARSET|COLLATE|COMMENT|;) 定位表的 ),避免字段 VARCHAR(128) 的 ) 让非贪婪 body 提前截断
|
|
72
|
-
// COMMENT 锚点:MySQL
|
|
73
|
-
|
|
72
|
+
// COMMENT 锚点:MySQL 表级注释是 `COMMENT='表注释'`(有等号),字段级注释是 `COMMENT '字段注释'`(空格无等号)。
|
|
73
|
+
// 终止锚点须用 COMMENT\s*= 只匹配表级——否则字段 `VARCHAR(64) COMMENT '简称'` 的 ) 后 COMMENT 误触发终止,body 提前截断致第5字段起全丢(waiver 81dd44a6 的真根因)。
|
|
74
|
+
const tableRe = /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?[`"]?(\w+)[`"]?\s*\(([\s\S]*?)\)\s*(?:ENGINE|DEFAULT|CHARSET|COLLATE|COMMENT\s*=|;)/gi;
|
|
74
75
|
let tm;
|
|
75
76
|
while ((tm = tableRe.exec(content)) !== null) {
|
|
76
77
|
const table = tm[1];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executors_field_mapping.js","sourceRoot":"","sources":["../../../src/gate/executors/executors_field_mapping.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"executors_field_mapping.js","sourceRoot":"","sources":["../../../src/gate/executors/executors_field_mapping.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** 扫描代码路由 → Map<path, Set<method>>。支持 Java Spring(@XxxMapping) 与 Node(express/fastify router.method)。 */
|
|
2
|
+
export declare function extractCodeRoutes(projectRoot: string, codeGlob: string): Map<string, Set<string>>;
|
|
3
|
+
/** 解析 openapi.yaml paths → Set<"METHOD path">。 */
|
|
4
|
+
export declare function parseOpenapiOps(content: string): Set<string>;
|
|
5
|
+
export declare function registerOpenapiConformanceExecutor(): void;
|
|
6
|
+
//# sourceMappingURL=executors_openapi_conformance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executors_openapi_conformance.d.ts","sourceRoot":"","sources":["../../../src/gate/executors/executors_openapi_conformance.ts"],"names":[],"mappings":"AAcA,yGAAyG;AACzG,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAqBjG;AAED,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAe5D;AAED,wBAAgB,kCAAkC,IAAI,IAAI,CAwCzD"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* openapi conformance 执行器 — 代码实现的 API 路由 ↔ openapi.yaml operation 一致性。
|
|
3
|
+
* 确定性偏差:实现层(代码↔契约)。破 code-first 反向生成覆盖契约——代码必须正面实现 openapi 声明的每个 operation。
|
|
4
|
+
* 无代码(build 未实现)→ skip。
|
|
5
|
+
*
|
|
6
|
+
* 被谁调用:gate_engine(openapi_conformance executor)
|
|
7
|
+
* 数据流:evidence_required[0]=openapi.yaml;evidence_required[1]=backend 下 Java 代码 glob → 对比 → CheckResult
|
|
8
|
+
*/
|
|
9
|
+
import { gateExecutors } from "../gate_executors.js";
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { resolveArtifactsByGlob } from "../../shared/glob_path.js";
|
|
13
|
+
/** 扫描代码路由 → Map<path, Set<method>>。支持 Java Spring(@XxxMapping) 与 Node(express/fastify router.method)。 */
|
|
14
|
+
export function extractCodeRoutes(projectRoot, codeGlob) {
|
|
15
|
+
const routes = new Map();
|
|
16
|
+
for (const rel of resolveArtifactsByGlob(projectRoot, codeGlob)) {
|
|
17
|
+
let content = "";
|
|
18
|
+
try {
|
|
19
|
+
content = readFileSync(join(projectRoot, rel), "utf-8");
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
// Java: 类级 @RequestMapping("/api/v1") 作前缀,方法级 @GetMapping("/users") 组合 → /api/v1/users
|
|
25
|
+
// (不组合则只剩 /users,与 openapi 的 /api/v1/users 对不上 → 全 operation 误报缺失)
|
|
26
|
+
const clsMatch = content.match(/@RequestMapping\s*\(\s*(?:value\s*=\s*)?["']([^"']+)["']/);
|
|
27
|
+
const prefix = clsMatch ? clsMatch[1] : "";
|
|
28
|
+
for (const m of content.matchAll(/@(Get|Post|Put|Patch|Delete)Mapping\s*\(\s*(?:value\s*=\s*)?["']([^"']+)["']/g)) {
|
|
29
|
+
const path = prefix + m[2];
|
|
30
|
+
if (!routes.has(path))
|
|
31
|
+
routes.set(path, new Set());
|
|
32
|
+
routes.get(path).add(m[1].toLowerCase());
|
|
33
|
+
}
|
|
34
|
+
// Node: router.get("/x", ...) / app.post("/x", ...)
|
|
35
|
+
for (const m of content.matchAll(/\.(get|post|put|patch|delete)\s*\(\s*["']([^"']+)["']/g)) {
|
|
36
|
+
const path = m[2];
|
|
37
|
+
if (!routes.has(path))
|
|
38
|
+
routes.set(path, new Set());
|
|
39
|
+
routes.get(path).add(m[1]);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return routes;
|
|
43
|
+
}
|
|
44
|
+
/** 解析 openapi.yaml paths → Set<"METHOD path">。 */
|
|
45
|
+
export function parseOpenapiOps(content) {
|
|
46
|
+
const ops = new Set();
|
|
47
|
+
let curPath = null;
|
|
48
|
+
let inPaths = false;
|
|
49
|
+
for (const raw of content.split("\n")) {
|
|
50
|
+
if (/^paths:\s*$/.test(raw)) {
|
|
51
|
+
inPaths = true;
|
|
52
|
+
curPath = null;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (!inPaths)
|
|
56
|
+
continue;
|
|
57
|
+
const line = raw.replace(/\s+$/, "");
|
|
58
|
+
if (line && !line.startsWith(" ") && !line.startsWith("#") && /^(components|servers|security|tags|externalDocs|info|openapi):/.test(line)) {
|
|
59
|
+
inPaths = false;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const pm = line.match(/^ (\/[^:]+):\s*$/);
|
|
63
|
+
if (pm) {
|
|
64
|
+
curPath = pm[1];
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (curPath === null)
|
|
68
|
+
continue;
|
|
69
|
+
const mm = line.match(/^ (get|post|put|patch|delete):/);
|
|
70
|
+
if (mm)
|
|
71
|
+
ops.add(`${mm[1].toUpperCase()} ${curPath}`);
|
|
72
|
+
}
|
|
73
|
+
return ops;
|
|
74
|
+
}
|
|
75
|
+
export function registerOpenapiConformanceExecutor() {
|
|
76
|
+
gateExecutors.register("openapi_conformance", async (check, ctx) => {
|
|
77
|
+
try {
|
|
78
|
+
const openapiRel = check.evidence_required?.[0] ?? "docs/api/openapi.yaml";
|
|
79
|
+
const codeGlob = check.evidence_required?.[1] ?? "backend/**/*.java";
|
|
80
|
+
const codeRoutes = extractCodeRoutes(ctx.projectRoot, codeGlob);
|
|
81
|
+
if (codeRoutes.size === 0) {
|
|
82
|
+
return { check_id: check.id, executed_by: "code", passed: true, skipped: true,
|
|
83
|
+
evidence: `无代码路由(${codeGlob} 未匹配,build 未实现),跳过 openapi conformance`,
|
|
84
|
+
metric: { passed: 0, total: 0, deviation_rate: 0 } };
|
|
85
|
+
}
|
|
86
|
+
let yamlContent = "";
|
|
87
|
+
try {
|
|
88
|
+
yamlContent = readFileSync(join(ctx.projectRoot, openapiRel), "utf-8");
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return { check_id: check.id, executed_by: "code", passed: true, skipped: true,
|
|
92
|
+
evidence: `openapi.yaml 不存在(${openapiRel}),跳过`, metric: { passed: 0, total: 0, deviation_rate: 0 } };
|
|
93
|
+
}
|
|
94
|
+
const yamlOps = parseOpenapiOps(yamlContent);
|
|
95
|
+
// 代码路由展开为 METHOD path 集合(类级 @RequestMapping 前缀已含在 path)
|
|
96
|
+
const codeOps = new Set();
|
|
97
|
+
for (const [path, methods] of codeRoutes) {
|
|
98
|
+
for (const me of methods)
|
|
99
|
+
codeOps.add(`${me.toUpperCase()} ${path}`);
|
|
100
|
+
}
|
|
101
|
+
const missing = [...yamlOps].filter((op) => !codeOps.has(op));
|
|
102
|
+
const deviationRate = yamlOps.size === 0 ? 0 : missing.length / yamlOps.size;
|
|
103
|
+
const passed = missing.length === 0;
|
|
104
|
+
return {
|
|
105
|
+
check_id: check.id, executed_by: "code", passed,
|
|
106
|
+
metric: { passed: yamlOps.size - missing.length, total: yamlOps.size, deviation_rate: deviationRate },
|
|
107
|
+
evidence: passed
|
|
108
|
+
? `openapi conformance:代码实现全部 ${yamlOps.size} 个 operation`
|
|
109
|
+
: `openapi 契约未实现:${yamlOps.size - missing.length}/${yamlOps.size} 有代码;缺 ${missing.slice(0, 5).join(", ")}`,
|
|
110
|
+
error: passed ? undefined : `代码未实现这些 openapi operation(实现偏差 ${(deviationRate * 100).toFixed(1)}%):${missing.slice(0, 3).join(", ")}`,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
return { check_id: check.id, executed_by: "code", passed: false,
|
|
115
|
+
error: `openapi_conformance 执行异常(fail-closed):${err instanceof Error ? err.message : String(err)}` };
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=executors_openapi_conformance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executors_openapi_conformance.js","sourceRoot":"","sources":["../../../src/gate/executors/executors_openapi_conformance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executors_proto_interaction.d.ts","sourceRoot":"","sources":["../../../src/gate/executors/executors_proto_interaction.ts"],"names":[],"mappings":"AAwBA,wBAAgB,gCAAgC,IAAI,IAAI,CA0CvD"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 原型交互覆盖率执行器 — 原型交互需求密度 vs API operation 供给的粗略比例信号(heuristic)。
|
|
3
|
+
*
|
|
4
|
+
* 确定性边界:原型无结构化交互声明(按钮/操作是自由文本),本 check 只给"交互密度 vs API 数"的
|
|
5
|
+
* 粗略比例信号,severity=warning(留痕不阻断)——比例失调(交互需求远多于 API 供给)提示可能漏接口。
|
|
6
|
+
* 精确的原型交互→API 映射需原型声明交互(未来增强),当前从交互关键词反推。
|
|
7
|
+
*
|
|
8
|
+
* 被谁调用:gate_engine(proto_interaction_coverage executor)
|
|
9
|
+
* 数据流:evidence_required=[原型 glob, openapi.yaml] → 交互关键词计数 vs operation 数 → CheckResult(warning + metric)
|
|
10
|
+
*/
|
|
11
|
+
import { gateExecutors } from "../gate_executors.js";
|
|
12
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { resolveArtifactsByGlob } from "../../shared/glob_path.js";
|
|
15
|
+
/** 原型交互关键词(自由文本反推交互需求)。 */
|
|
16
|
+
const INTERACTION_RE = /(?:按钮|编辑|新增|删除|修改|更新|导出|查询|搜索|提交|确认|审批|上传|下载|选择|切换|勾选|点击|登录|登出|支付|结算)/g;
|
|
17
|
+
/** 统计 openapi.yaml operation 数。 */
|
|
18
|
+
function countOpenapiOps(content) {
|
|
19
|
+
return (content.match(/^ (get|post|put|patch|delete):/gm) ?? []).length;
|
|
20
|
+
}
|
|
21
|
+
export function registerProtoInteractionExecutor() {
|
|
22
|
+
gateExecutors.register("proto_interaction_coverage", async (check, ctx) => {
|
|
23
|
+
try {
|
|
24
|
+
const protoGlob = check.evidence_required?.[0] ?? "docs/analyze/*/pages/*-原型说明.md";
|
|
25
|
+
const openapiRel = check.evidence_required?.[1] ?? "docs/api/openapi.yaml";
|
|
26
|
+
const protoFiles = resolveArtifactsByGlob(ctx.projectRoot, protoGlob);
|
|
27
|
+
if (protoFiles.length === 0) {
|
|
28
|
+
return { check_id: check.id, executed_by: "code", passed: true, skipped: true,
|
|
29
|
+
evidence: `无原型(${protoGlob},scope≠frontend),跳过`, metric: { passed: 0, total: 0, deviation_rate: 0 } };
|
|
30
|
+
}
|
|
31
|
+
let interactionCount = 0;
|
|
32
|
+
for (const rel of protoFiles) {
|
|
33
|
+
try {
|
|
34
|
+
interactionCount += (readFileSync(join(ctx.projectRoot, rel), "utf-8").match(INTERACTION_RE) ?? []).length;
|
|
35
|
+
}
|
|
36
|
+
catch { /* skip */ }
|
|
37
|
+
}
|
|
38
|
+
const yamlAbs = join(ctx.projectRoot, openapiRel);
|
|
39
|
+
if (!existsSync(yamlAbs)) {
|
|
40
|
+
return { check_id: check.id, executed_by: "code", passed: true, skipped: true,
|
|
41
|
+
evidence: "无 openapi.yaml,跳过", metric: { passed: 0, total: 0, deviation_rate: 0 } };
|
|
42
|
+
}
|
|
43
|
+
const opCount = countOpenapiOps(readFileSync(yamlAbs, "utf-8"));
|
|
44
|
+
if (interactionCount === 0) {
|
|
45
|
+
return { check_id: check.id, executed_by: "code", passed: true,
|
|
46
|
+
evidence: "原型无交互关键词,跳过", metric: { passed: 0, total: 0, deviation_rate: 0 } };
|
|
47
|
+
}
|
|
48
|
+
// 粗略比例:API operation / 交互需求。比例 < 0.3 视为交互需求远多于 API 供给(可能漏接口)。
|
|
49
|
+
const ratio = opCount / interactionCount;
|
|
50
|
+
const deviationRate = Math.max(0, 1 - ratio / 0.5); // 以 1:2(每2交互1API)为合理基线
|
|
51
|
+
const passed = ratio >= 0.3;
|
|
52
|
+
return {
|
|
53
|
+
check_id: check.id, executed_by: "code", passed,
|
|
54
|
+
metric: { passed: opCount, total: interactionCount, deviation_rate: Math.min(1, deviationRate) },
|
|
55
|
+
evidence: `原型交互关键词 ${interactionCount} vs openapi operation ${opCount}(比例 ${(ratio * 100).toFixed(0)}%)${passed ? ",比例合理" : ",交互需求远多于 API 供给,疑似漏接口"}`,
|
|
56
|
+
error: passed ? undefined : `原型交互密度 vs API 比例失调(${(ratio * 100).toFixed(0)}%,heuristic 信号,warning)`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
return { check_id: check.id, executed_by: "code", passed: false,
|
|
61
|
+
error: `proto_interaction_coverage 执行异常(fail-closed):${err instanceof Error ? err.message : String(err)}` };
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=executors_proto_interaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executors_proto_interaction.js","sourceRoot":"","sources":["../../../src/gate/executors/executors_proto_interaction.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executors_required_artifact.d.ts","sourceRoot":"","sources":["../../../src/gate/executors/executors_required_artifact.ts"],"names":[],"mappings":"AAcA,wBAAgB,gCAAgC,IAAI,IAAI,CAoCvD"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 必产物存在性执行器 — 校验 evidence_required 列出的产物文件都存在(通用)。
|
|
3
|
+
*
|
|
4
|
+
* 用途:ADR-EXISTS(架构决策记录须存在)等"产物文件存在性"硬校验。
|
|
5
|
+
* 区别 file_evidence:file_evidence 校验运行时证据目录(截图/json),本 executor 校验源产物文件。
|
|
6
|
+
*
|
|
7
|
+
* 被谁调用:gate_engine(required_artifact_check executor)
|
|
8
|
+
* 数据流:evidence_required=[产物路径...] → existsSync 逐个 → CheckResult(含 metric)
|
|
9
|
+
*/
|
|
10
|
+
import { gateExecutors } from "../gate_executors.js";
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
export function registerRequiredArtifactExecutor() {
|
|
14
|
+
gateExecutors.register("required_artifact_check", async (check, ctx) => {
|
|
15
|
+
try {
|
|
16
|
+
const reqs = check.evidence_required ?? [];
|
|
17
|
+
if (reqs.length === 0) {
|
|
18
|
+
return { check_id: check.id, executed_by: "code", passed: true, skipped: true,
|
|
19
|
+
evidence: "无 evidence_required,跳过", metric: { passed: 0, total: 0, deviation_rate: 0 } };
|
|
20
|
+
}
|
|
21
|
+
// 多文件时,第一个为前提产物(如架构文档);前提未产出 → 阶段未到,skip(不 fail,防 verify requirement_analysis 时误拦)
|
|
22
|
+
let targets = reqs;
|
|
23
|
+
if (reqs.length > 1) {
|
|
24
|
+
if (!existsSync(join(ctx.projectRoot, reqs[0]))) {
|
|
25
|
+
return { check_id: check.id, executed_by: "code", passed: true, skipped: true,
|
|
26
|
+
evidence: `前提产物 ${reqs[0]} 未产出(阶段未到),跳过`, metric: { passed: 0, total: 0, deviation_rate: 0 } };
|
|
27
|
+
}
|
|
28
|
+
targets = reqs.slice(1);
|
|
29
|
+
}
|
|
30
|
+
const missing = [];
|
|
31
|
+
for (const rel of targets) {
|
|
32
|
+
if (!existsSync(join(ctx.projectRoot, rel)))
|
|
33
|
+
missing.push(rel);
|
|
34
|
+
}
|
|
35
|
+
const passed = missing.length === 0;
|
|
36
|
+
return {
|
|
37
|
+
check_id: check.id, executed_by: "code", passed,
|
|
38
|
+
metric: { passed: targets.length - missing.length, total: targets.length, deviation_rate: missing.length / targets.length },
|
|
39
|
+
evidence: passed ? `必产物全部存在:${targets.length}/${targets.length}` : `必产物缺失:${missing.join(", ")}`,
|
|
40
|
+
error: passed ? undefined : `必产物文件不存在:${missing.join(", ")}`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
return { check_id: check.id, executed_by: "code", passed: false,
|
|
45
|
+
error: `required_artifact_check 执行异常(fail-closed):${err instanceof Error ? err.message : String(err)}` };
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=executors_required_artifact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executors_required_artifact.js","sourceRoot":"","sources":["../../../src/gate/executors/executors_required_artifact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** 解析 SQL 的 CREATE TABLE → Map<表, Set<字段>>。复用 FMAP 修复后的 COMMENT= 锚点。 */
|
|
2
|
+
export declare function parseTables(content: string): Map<string, Set<string>>;
|
|
3
|
+
export declare function registerSchemaConformanceExecutor(): void;
|
|
4
|
+
//# sourceMappingURL=executors_schema_conformance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executors_schema_conformance.d.ts","sourceRoot":"","sources":["../../../src/gate/executors/executors_schema_conformance.ts"],"names":[],"mappings":"AAcA,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAerE;AAED,wBAAgB,iCAAiC,IAAI,IAAI,CA6CxD"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* schema conformance 执行器 — Flyway migration 建表 ↔ schema.sql 表/字段一致性。
|
|
3
|
+
* 确定性偏差:实现层(数据↔契约)。migration 实际建表须与权威 schema.sql 一致。
|
|
4
|
+
* 无 migration(build 未实现)→ skip。
|
|
5
|
+
*
|
|
6
|
+
* 被谁调用:gate_engine(schema_conformance executor)
|
|
7
|
+
* 数据流:evidence_required[0]=schema.sql;evidence_required[1]=backend 下 migration V*.sql glob → 对比 → CheckResult
|
|
8
|
+
*/
|
|
9
|
+
import { gateExecutors } from "../gate_executors.js";
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { resolveArtifactsByGlob } from "../../shared/glob_path.js";
|
|
13
|
+
/** 解析 SQL 的 CREATE TABLE → Map<表, Set<字段>>。复用 FMAP 修复后的 COMMENT= 锚点。 */
|
|
14
|
+
export function parseTables(content) {
|
|
15
|
+
const tables = new Map();
|
|
16
|
+
const tableRe = /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?[`"]?(\w+)[`"]?\s*\(([\s\S]*?)\)\s*(?:ENGINE|DEFAULT|CHARSET|COLLATE|COMMENT\s*=|;)/gi;
|
|
17
|
+
let m;
|
|
18
|
+
while ((m = tableRe.exec(content)) !== null) {
|
|
19
|
+
const fields = new Set();
|
|
20
|
+
for (const line of m[2].split(/[,\n]/)) {
|
|
21
|
+
const t = line.trim();
|
|
22
|
+
if (!t || /\b(KEY|CONSTRAINT|PRIMARY|FOREIGN|UNIQUE|INDEX|CHECK)\b/i.test(t))
|
|
23
|
+
continue;
|
|
24
|
+
const fm = t.match(/^[`"]?(\w+)[`"]?\s+/);
|
|
25
|
+
if (fm)
|
|
26
|
+
fields.add(fm[1]);
|
|
27
|
+
}
|
|
28
|
+
tables.set(m[1], fields);
|
|
29
|
+
}
|
|
30
|
+
return tables;
|
|
31
|
+
}
|
|
32
|
+
export function registerSchemaConformanceExecutor() {
|
|
33
|
+
gateExecutors.register("schema_conformance", async (check, ctx) => {
|
|
34
|
+
try {
|
|
35
|
+
const schemaRel = check.evidence_required?.[0] ?? "docs/design/schema.sql";
|
|
36
|
+
const migGlob = check.evidence_required?.[1] ?? "backend/**/migration/V*.sql";
|
|
37
|
+
const migFiles = resolveArtifactsByGlob(ctx.projectRoot, migGlob);
|
|
38
|
+
if (migFiles.length === 0) {
|
|
39
|
+
return { check_id: check.id, executed_by: "code", passed: true, skipped: true,
|
|
40
|
+
evidence: `无 Flyway migration(${migGlob} 未匹配,build 未实现),跳过 schema conformance`,
|
|
41
|
+
metric: { passed: 0, total: 0, deviation_rate: 0 } };
|
|
42
|
+
}
|
|
43
|
+
const migContent = migFiles.map((r) => { try {
|
|
44
|
+
return readFileSync(join(ctx.projectRoot, r), "utf-8");
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return "";
|
|
48
|
+
} }).join("\n");
|
|
49
|
+
const migTables = parseTables(migContent);
|
|
50
|
+
let schemaContent = "";
|
|
51
|
+
try {
|
|
52
|
+
schemaContent = readFileSync(join(ctx.projectRoot, schemaRel), "utf-8");
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return { check_id: check.id, executed_by: "code", passed: false, error: `schema.sql 不存在: ${schemaRel}` };
|
|
56
|
+
}
|
|
57
|
+
const schemaTables = parseTables(schemaContent);
|
|
58
|
+
// 对比:migration 建的表须在 schema.sql,字段一致
|
|
59
|
+
const problems = [];
|
|
60
|
+
let consistent = 0;
|
|
61
|
+
for (const [tbl, fields] of migTables) {
|
|
62
|
+
const sf = schemaTables.get(tbl);
|
|
63
|
+
if (!sf) {
|
|
64
|
+
problems.push(`migration 建表 ${tbl} 不在 schema.sql`);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const missing = [...fields].filter((f) => !sf.has(f));
|
|
68
|
+
if (missing.length === 0)
|
|
69
|
+
consistent++;
|
|
70
|
+
else
|
|
71
|
+
problems.push(`${tbl} 字段不一致(缺 ${missing.slice(0, 3).join(",")})`);
|
|
72
|
+
}
|
|
73
|
+
const total = migTables.size;
|
|
74
|
+
const deviationRate = total === 0 ? 0 : (total - consistent) / total;
|
|
75
|
+
const passed = problems.length === 0;
|
|
76
|
+
return {
|
|
77
|
+
check_id: check.id, executed_by: "code", passed,
|
|
78
|
+
metric: { passed: consistent, total, deviation_rate: deviationRate },
|
|
79
|
+
evidence: passed
|
|
80
|
+
? `schema conformance:${consistent}/${total} migration 表与 schema.sql 一致`
|
|
81
|
+
: `migration↔schema.sql 不一致:${consistent}/${total};${problems.slice(0, 5).join("; ")}`,
|
|
82
|
+
error: passed ? undefined : `migration 建表与权威 schema.sql 偏差(实现偏差 ${(deviationRate * 100).toFixed(1)}%)`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
return { check_id: check.id, executed_by: "code", passed: false,
|
|
87
|
+
error: `schema_conformance 执行异常(fail-closed):${err instanceof Error ? err.message : String(err)}` };
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=executors_schema_conformance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executors_schema_conformance.js","sourceRoot":"","sources":["../../../src/gate/executors/executors_schema_conformance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executors_section_integrity.d.ts","sourceRoot":"","sources":["../../../src/gate/executors/executors_section_integrity.ts"],"names":[],"mappings":"AAsCA,wBAAgB,gCAAgC,IAAI,IAAI,CAmDvD"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* section 完整性执行器 — 校验架构设计文档指定 section(§4 模块划分 / §9 状态机)有结构化内容(表格/状态图),非 bullet 空话。
|
|
3
|
+
*
|
|
4
|
+
* 确定性偏差:design_doc 结构强度。补 §4/§9 的结构约束——block_check 切块语义(匹配行到下个匹配)对单 section 不精确
|
|
5
|
+
* (§4 块会含 §5-8),故用按 ## 精确切 section + 指定 section 校验。
|
|
6
|
+
*
|
|
7
|
+
* 被谁调用:gate_engine(section_integrity_check executor)
|
|
8
|
+
* 数据流:evidence_required[0]=架构设计文档 → 切 ## section → §4 须表格≥3 行,§9 须 stateDiagram+状态表 → CheckResult
|
|
9
|
+
*/
|
|
10
|
+
import { gateExecutors } from "../gate_executors.js";
|
|
11
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
/** 按 ## 切 section → [{title, body}]。 */
|
|
14
|
+
function splitSections(content) {
|
|
15
|
+
const sections = [];
|
|
16
|
+
let cur = null;
|
|
17
|
+
for (const l of content.split("\n")) {
|
|
18
|
+
if (/^##\s/.test(l)) {
|
|
19
|
+
if (cur)
|
|
20
|
+
sections.push({ title: cur.title, body: cur.body.join("\n") });
|
|
21
|
+
cur = { title: l, body: [] };
|
|
22
|
+
}
|
|
23
|
+
else if (cur)
|
|
24
|
+
cur.body.push(l);
|
|
25
|
+
}
|
|
26
|
+
if (cur)
|
|
27
|
+
sections.push({ title: cur.title, body: cur.body.join("\n") });
|
|
28
|
+
return sections;
|
|
29
|
+
}
|
|
30
|
+
function findSectionBody(sections, re) {
|
|
31
|
+
const s = sections.find((x) => re.test(x.title));
|
|
32
|
+
return s ? s.body : null;
|
|
33
|
+
}
|
|
34
|
+
/** 表格数据行:含 | 且非分隔行(纯 |/ -/:/空格)。 */
|
|
35
|
+
function countTableDataRows(text) {
|
|
36
|
+
return text.split("\n").filter((l) => l.includes("|") && !/^\s*\|?[\s\-:|]+\|?\s*$/.test(l)).length;
|
|
37
|
+
}
|
|
38
|
+
export function registerSectionIntegrityExecutor() {
|
|
39
|
+
gateExecutors.register("section_integrity_check", async (check, ctx) => {
|
|
40
|
+
try {
|
|
41
|
+
const archRel = check.evidence_required?.[0] ?? "docs/architecture/01-架构设计文档.md";
|
|
42
|
+
const abs = join(ctx.projectRoot, archRel);
|
|
43
|
+
if (!existsSync(abs)) {
|
|
44
|
+
return { check_id: check.id, executed_by: "code", passed: true, skipped: true,
|
|
45
|
+
evidence: `架构文档未产出(${archRel}),跳过 section 完整性` };
|
|
46
|
+
}
|
|
47
|
+
const sections = splitSections(readFileSync(abs, "utf-8"));
|
|
48
|
+
const problems = [];
|
|
49
|
+
let checked = 0;
|
|
50
|
+
let ok = 0;
|
|
51
|
+
const s4 = findSectionBody(sections, /^##\s+4\b/);
|
|
52
|
+
if (s4 !== null) {
|
|
53
|
+
checked++;
|
|
54
|
+
const rows = countTableDataRows(s4);
|
|
55
|
+
if (rows >= 3)
|
|
56
|
+
ok++;
|
|
57
|
+
else
|
|
58
|
+
problems.push(`§4 模块划分表格数据行不足(${rows}/3,禁 bullet 空话)`);
|
|
59
|
+
}
|
|
60
|
+
const s9 = findSectionBody(sections, /^##\s+9\b/);
|
|
61
|
+
if (s9 !== null) {
|
|
62
|
+
checked++;
|
|
63
|
+
const hasState = /stateDiagram(-v2)?/.test(s9);
|
|
64
|
+
const rows = countTableDataRows(s9);
|
|
65
|
+
if (hasState && rows >= 2)
|
|
66
|
+
ok++;
|
|
67
|
+
else {
|
|
68
|
+
const miss = [];
|
|
69
|
+
if (!hasState)
|
|
70
|
+
miss.push("Mermaid stateDiagram");
|
|
71
|
+
if (rows < 2)
|
|
72
|
+
miss.push(`状态表(${rows}/2 行)`);
|
|
73
|
+
problems.push(`§9 状态机缺 ${miss.join(" + ")}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (checked === 0) {
|
|
77
|
+
return { check_id: check.id, executed_by: "code", passed: true, skipped: true,
|
|
78
|
+
evidence: "架构无 §4/§9 section(章节存在由 ARCH-STRUCT 管),跳过",
|
|
79
|
+
metric: { passed: 0, total: 0, deviation_rate: 0 } };
|
|
80
|
+
}
|
|
81
|
+
const passed = problems.length === 0;
|
|
82
|
+
return {
|
|
83
|
+
check_id: check.id, executed_by: "code", passed,
|
|
84
|
+
metric: { passed: ok, total: checked, deviation_rate: (checked - ok) / checked },
|
|
85
|
+
evidence: passed ? `section 完整:§4/§9 均有结构化内容(表格/状态图)` : `section 不完整:${problems.join(";")}`,
|
|
86
|
+
error: passed ? undefined : `架构 §4/§9 缺结构化内容(${problems.join(";")})`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
return { check_id: check.id, executed_by: "code", passed: false,
|
|
91
|
+
error: `section_integrity_check 执行异常(fail-closed):${err instanceof Error ? err.message : String(err)}` };
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=executors_section_integrity.js.map
|