soloforge 1.3.3 → 1.3.4

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.
Files changed (75) hide show
  1. package/README.md +9 -0
  2. package/dist/adapters/claude_code/server.js +1 -1
  3. package/dist/adapters/claude_code/server.js.map +1 -1
  4. package/dist/adapters/claude_code/tools.d.ts.map +1 -1
  5. package/dist/adapters/claude_code/tools.js +109 -25
  6. package/dist/adapters/claude_code/tools.js.map +1 -1
  7. package/dist/adapters/shared/workflow_template.js +2 -2
  8. package/dist/adapters/shared/workflow_template.js.map +1 -1
  9. package/dist/bin/soloforge.js +65 -0
  10. package/dist/bin/soloforge.js.map +1 -1
  11. package/dist/engine/asset_manifest.d.ts.map +1 -1
  12. package/dist/engine/asset_manifest.js +11 -0
  13. package/dist/engine/asset_manifest.js.map +1 -1
  14. package/dist/engine/code_maintainability_observability_contract.d.ts +74 -0
  15. package/dist/engine/code_maintainability_observability_contract.d.ts.map +1 -0
  16. package/dist/engine/code_maintainability_observability_contract.js +473 -0
  17. package/dist/engine/code_maintainability_observability_contract.js.map +1 -0
  18. package/dist/engine/config_write_boundary.d.ts +29 -0
  19. package/dist/engine/config_write_boundary.d.ts.map +1 -0
  20. package/dist/engine/config_write_boundary.js +69 -0
  21. package/dist/engine/config_write_boundary.js.map +1 -0
  22. package/dist/engine/consumable_asset_registry.d.ts.map +1 -1
  23. package/dist/engine/consumable_asset_registry.js +49 -1
  24. package/dist/engine/consumable_asset_registry.js.map +1 -1
  25. package/dist/engine/diagnostic_registry.d.ts +12 -0
  26. package/dist/engine/diagnostic_registry.d.ts.map +1 -1
  27. package/dist/engine/diagnostic_registry.js +62 -0
  28. package/dist/engine/diagnostic_registry.js.map +1 -1
  29. package/dist/engine/dual_layer_mechanism_registry.d.ts.map +1 -1
  30. package/dist/engine/dual_layer_mechanism_registry.js +194 -1
  31. package/dist/engine/dual_layer_mechanism_registry.js.map +1 -1
  32. package/dist/engine/explicit_asset_registry.d.ts.map +1 -1
  33. package/dist/engine/explicit_asset_registry.js +134 -0
  34. package/dist/engine/explicit_asset_registry.js.map +1 -1
  35. package/dist/engine/implementation_roadmap_registry.d.ts.map +1 -1
  36. package/dist/engine/implementation_roadmap_registry.js +45 -1
  37. package/dist/engine/implementation_roadmap_registry.js.map +1 -1
  38. package/dist/engine/knowledge_governance_gate.d.ts +38 -0
  39. package/dist/engine/knowledge_governance_gate.d.ts.map +1 -0
  40. package/dist/engine/knowledge_governance_gate.js +123 -0
  41. package/dist/engine/knowledge_governance_gate.js.map +1 -0
  42. package/dist/engine/log_governance.d.ts +25 -0
  43. package/dist/engine/log_governance.d.ts.map +1 -0
  44. package/dist/engine/log_governance.js +76 -0
  45. package/dist/engine/log_governance.js.map +1 -0
  46. package/dist/engine/mechanism_contract_registry.d.ts +1 -0
  47. package/dist/engine/mechanism_contract_registry.d.ts.map +1 -1
  48. package/dist/engine/mechanism_contract_registry.js +104 -0
  49. package/dist/engine/mechanism_contract_registry.js.map +1 -1
  50. package/dist/engine/mechanism_health_check.d.ts +23 -0
  51. package/dist/engine/mechanism_health_check.d.ts.map +1 -0
  52. package/dist/engine/mechanism_health_check.js +140 -0
  53. package/dist/engine/mechanism_health_check.js.map +1 -0
  54. package/dist/engine/observability.js +1 -1
  55. package/dist/engine/observability.js.map +1 -1
  56. package/dist/engine/release_issue_scenario_registry.d.ts.map +1 -1
  57. package/dist/engine/release_issue_scenario_registry.js +216 -0
  58. package/dist/engine/release_issue_scenario_registry.js.map +1 -1
  59. package/dist/engine/release_readiness_gate.d.ts +3 -0
  60. package/dist/engine/release_readiness_gate.d.ts.map +1 -1
  61. package/dist/engine/release_readiness_gate.js +260 -8
  62. package/dist/engine/release_readiness_gate.js.map +1 -1
  63. package/dist/engine/team_awareness.js +6 -6
  64. package/dist/engine/team_awareness.js.map +1 -1
  65. package/dist/types.d.ts +4 -0
  66. package/dist/types.d.ts.map +1 -1
  67. package/package.json +1 -1
  68. 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
  69. 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
  70. 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 +121 -0
  71. 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
  72. 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
  73. 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
  74. 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
  75. 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
@@ -21,6 +21,9 @@
21
21
  * 13. 第五批一致性校验
22
22
  * 14. 依赖漏洞扫描
23
23
  * 15. 发布问题架构决策与设计产物真实消费
24
+ * 18. 代码可维护性与可观测性契约行为验证
25
+ * 19. 历史问题长期机制化行为验证
26
+ * 20. 诊断码集中治理检查
24
27
  */
25
28
  import fs from "node:fs";
26
29
  import os from "node:os";
@@ -1136,13 +1139,13 @@ async function checkBatchIssueFormatConsistency(rootDir, hardFail, _info) {
1136
1139
  hardFail("BATCH_ISSUE_FORMAT_INCONSISTENT", "loadBatchIssueDetails 导出未找到", ["scripts/batch_issue_details.mjs"], "构建系统", "共享解析脚本导出不正确", "修复脚本");
1137
1140
  return;
1138
1141
  }
1139
- const expectedCounts = { 1: 19, 2: 12, 3: 9, 4: 13, 5: 6, 6: 5, 7: 2 };
1142
+ const expectedCounts = { 1: 19, 2: 12, 3: 9, 4: 13, 5: 6, 6: 5, 7: 2, 8: 1 };
1140
1143
  const requiredPerProblemSections = [
1141
1144
  "问题背景", "用户反馈 / 触发场景", "根因分析", "解决方案", "方案细节",
1142
1145
  "硬规则", "非目标", "影响范围", "落地文件", "验收标准", "回归风险",
1143
1146
  "与其他问题的关联", "发布门禁要求",
1144
1147
  ];
1145
- for (let batch = 1; batch <= 7; batch++) {
1148
+ for (let batch = 1; batch <= 8; batch++) {
1146
1149
  const details = loadBatchIssueDetails(batch, rootDir);
1147
1150
  if (!details.loaded) {
1148
1151
  hardFail("BATCH_ISSUE_FORMAT_INCONSISTENT", `Batch${batch} 问题集未加载: ${details.error}`, [`docs/SoloForge-Batch${batch}问题集.md`], `Batch${batch}`, "旧 gate 只检查文档存在,不验证是否可解析", "第 3 步统一格式");
@@ -1341,7 +1344,7 @@ async function checkKnowledgeAssetSchema(rootDir, hardFail, _info) {
1341
1344
  }
1342
1345
  }
1343
1346
  }
1344
- // ── Phase 11: engine console.log 检查 ──
1347
+ // ── Phase 11: engine console 直写检查 ──
1345
1348
  function checkEngineConsoleLog(rootDir, hardFail) {
1346
1349
  // 扫描全 src/ 目录(不仅 engine)
1347
1350
  const srcDir = path.join(rootDir, "src");
@@ -1359,12 +1362,13 @@ function checkEngineConsoleLog(rootDir, hardFail) {
1359
1362
  continue;
1360
1363
  if (/"console\.log"|`console\.log`|'console\.log'|console\\.log/.test(line))
1361
1364
  continue;
1362
- // 日志模块内部 stdout 封装允许 console.log
1363
- if (/logger\.ts$/.test(file) && /^\s*console\.log\(/.test(line))
1365
+ // 日志模块内部 stdout/stderr 封装允许 console.log / console.error
1366
+ if (/logger\.ts$/.test(file) && /^\s*console\.(log|error)\(/.test(line))
1364
1367
  continue;
1365
- if (/console\.log\s*\(/.test(line)) {
1368
+ const directConsole = line.match(/console\.(log|warn|error|debug)\s*\(/);
1369
+ if (directConsole) {
1366
1370
  const rel = path.relative(rootDir, file);
1367
- hardFail("ENGINE_CONSOLE_LOG", `${rel}:${i + 1} 使用 console.log(应使用 logger console.error 写 stderr)`, [rel], "发布门禁 console 检查", "旧 gate 不检查 src/ 全目录 console.log", "替换为 logger 模块调用");
1371
+ hardFail("ENGINE_DIRECT_CONSOLE", `${rel}:${i + 1} 使用 console.${directConsole[1]}(应使用 logger 模块)`, [rel], "发布门禁 console 检查", "旧 gate 不检查 src/ 全目录 console 直写", "替换为 logger 模块调用");
1368
1372
  }
1369
1373
  }
1370
1374
  }
@@ -1693,6 +1697,7 @@ async function checkReleaseIssueDesignPath(rootDir, hardFail, _info) {
1693
1697
  "problem-62": ["release-scenario-design-pack-"],
1694
1698
  "problem-63": ["release-scenario-template-contract-"],
1695
1699
  "problem-64": ["release-scenario-template-visibility-"],
1700
+ "problem-68": ["release-scenario-code-observability-"],
1696
1701
  };
1697
1702
  for (const [problem, prefixes] of Object.entries(problemPrefixes)) {
1698
1703
  const problemScenarios = execResults.filter(r => prefixes.some(p => r.scenario_id.startsWith(p)));
@@ -1988,7 +1993,7 @@ async function checkReleaseIssueDesignPath(rootDir, hardFail, _info) {
1988
1993
  hardFail("RELEASE_ISSUE_CONTRACT_MISSING", "问题六十三缺少模板契约匹配、产物验证或修复重验函数", ["src/engine/standard_asset_contract.ts"], "problem-63", "缺少核心函数不能实现契约验证", "实现 matchTemplateContract / verifyOutputAgainstContract / createRepairReverifyDirective");
1989
1994
  }
1990
1995
  // sf_verify 必须按文件逐一匹配契约(不得使用 changed_files[0] 的契约校验全部文件)
1991
- if (!toolsText.includes("lazyStandardAssetContract") || !toolsText.includes("SF-CONTRACT-0003") || !toolsText.includes("repair_reverify_directive")) {
1996
+ if (!toolsText.includes("lazyStandardAssetContract") || !toolsText.includes("TOOL_DIAGNOSTIC_CODES.contractDraft") || !toolsText.includes("repair_reverify_directive")) {
1992
1997
  hardFail("RELEASE_ISSUE_CONTRACT_MAINLINE_MISSING", "问题六十三未接入 sf_verify 模板契约验证和 sf_deliver 修复重验阻断", ["src/adapters/claude_code/tools.ts"], "problem-63", "仅有契约定义不能阻断交付", "在 sf_verify 消费模板契约验证、sf_deliver 消费修复重验阻断");
1993
1998
  }
1994
1999
  // 必须检查 per-file 匹配(不得 changed_files[0] 统一匹配)
@@ -2217,6 +2222,241 @@ async function checkReleaseIssueDesignPath(rootDir, hardFail, _info) {
2217
2222
  }
2218
2223
  }
2219
2224
  }
2225
+ // ── 18. 代码可维护性与可观测性契约行为验证(问题六十八) ──
2226
+ async function checkCodeObservabilityBehavior(rootDir, hardFail, _info) {
2227
+ const obsPath = path.join(rootDir, "dist", "engine", "code_maintainability_observability_contract.js");
2228
+ if (!fs.existsSync(obsPath)) {
2229
+ hardFail("CODE_OBSERVABILITY_MODULE_MISSING", "problem-68: code_maintainability_observability_contract.js 未编译到 dist/", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "发布门禁不检查问题-68 实现是否存在", "实现 code_maintainability_observability_contract 并编译");
2230
+ return;
2231
+ }
2232
+ let obs;
2233
+ try {
2234
+ obs = await import(obsPath);
2235
+ }
2236
+ catch (e) {
2237
+ hardFail("CODE_OBSERVABILITY_IMPORT_ERROR", `problem-68: code_maintainability_observability_contract 导入失败: ${e.message}`, ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "可观测性模块存在但不可导入", "修复导入错误");
2238
+ return;
2239
+ }
2240
+ // 核心导出存在性
2241
+ const requiredExports = ["reviewMissingLogs", "detectSensitiveLogs", "reviewCommentQuality", "hasBlockingObservabilityFindings", "requiresCodeObservabilityContract", "isLowRiskChange", "detectProjectLogger", "verifyChangedFilesObservability", "evaluateDeliveryBlock"];
2242
+ for (const exp of requiredExports) {
2243
+ if (typeof obs[exp] !== "function") {
2244
+ hardFail("CODE_OBSERVABILITY_EXPORT_MISSING", `problem-68: code_maintainability_observability_contract.ts 缺少导出函数: ${exp}`, ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "可观测性模块缺少核心导出", `添加 ${exp} 导出`);
2245
+ }
2246
+ }
2247
+ // 行为验证: 支付写操作无日志必须被检测
2248
+ try {
2249
+ const paymentFindings = obs.reviewMissingLogs({
2250
+ "PaymentService.java": `public void refund(String orderId, BigDecimal amount) {
2251
+ orderRepository.save(order);
2252
+ paymentGateway.refund(orderId, amount);
2253
+ }`,
2254
+ });
2255
+ if (!obs.hasBlockingObservabilityFindings(paymentFindings)) {
2256
+ hardFail("CODE_OBSERVABILITY_PAYMENT_FALSE_PASS", "problem-68: 支付写操作无日志未被检测到", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "文件存在不能证明审查能力有效", "修复 reviewMissingLogs 检测逻辑");
2257
+ }
2258
+ // 行为验证: catch 吞异常无日志必须被检测
2259
+ const catchFindings = obs.reviewMissingLogs({
2260
+ "OrderService.ts": `async processOrder(orderId: string) {
2261
+ try {
2262
+ await this.client.submit(orderId);
2263
+ } catch (e) {
2264
+ return false;
2265
+ }
2266
+ }`,
2267
+ });
2268
+ if (!obs.hasBlockingObservabilityFindings(catchFindings)) {
2269
+ hardFail("CODE_OBSERVABILITY_CATCH_FALSE_PASS", "problem-68: catch 吞异常无日志未被检测到", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "catch 吞异常必须产生阻断 finding", "修复 reviewMissingLogs 检测逻辑");
2270
+ }
2271
+ // 行为验证: 敏感信息日志泄漏必须被检测
2272
+ const sensitiveFindings = obs.detectSensitiveLogs({
2273
+ "UserService.ts": `function login(user) {
2274
+ logger.info("user login", { token: "eyJhbGciOiJIUzI1NiJ9.xxxxx", password: user.password, phone: "13812345678" });
2275
+ }`,
2276
+ });
2277
+ if (!obs.hasBlockingObservabilityFindings(sensitiveFindings)) {
2278
+ hardFail("CODE_OBSERVABILITY_SENSITIVE_FALSE_PASS", "problem-68: 敏感信息日志泄漏未被检测到", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "token/password/手机号泄漏必须被阻断", "修复 detectSensitiveLogs 检测逻辑");
2279
+ }
2280
+ // 行为验证: 低风险任务不应触发
2281
+ const notTriggered = !obs.requiresCodeObservabilityContract("修复 README 错别字", "code_change");
2282
+ if (!notTriggered) {
2283
+ hardFail("CODE_OBSERVABILITY_LOW_RISK_OVERBLOCK", "problem-68: 低风险文案任务错误触发可观测性检查", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "低风险任务不应触发检查", "修复 requiresCodeObservabilityContract 判断逻辑");
2284
+ }
2285
+ // 行为验证: 项目 logger 类型检测
2286
+ const javaLogger = obs.detectProjectLogger({
2287
+ "Application.java": "import org.slf4j.LoggerFactory; private static final Logger log = LoggerFactory.getLogger(App.class);",
2288
+ });
2289
+ if (javaLogger.type !== "slf4j") {
2290
+ hardFail("CODE_OBSERVABILITY_LOGGER_DETECT_FAIL", `problem-68: SLF4J logger 未被正确识别 (got: ${javaLogger.type})`, ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "项目 logger 类型检测必须准确", "修复 detectProjectLogger 逻辑");
2291
+ }
2292
+ // 行为验证: 迁移脚本无审计日志必须被检测
2293
+ const migrationFindings = obs.reviewMissingLogs({
2294
+ "scripts/data_fix_order_status.ts": `async function migrateOrderStatus() {
2295
+ const orders = await db.query("SELECT * FROM orders WHERE status IS NULL");
2296
+ for (const order of orders) {
2297
+ await db.update("UPDATE orders SET status = 'pending' WHERE id = ?", [order.id]);
2298
+ }
2299
+ }`,
2300
+ });
2301
+ if (!obs.hasBlockingObservabilityFindings(migrationFindings)) {
2302
+ hardFail("CODE_OBSERVABILITY_MIGRATION_FALSE_PASS", "problem-68: 迁移脚本无审计日志未被检测到", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "数据修复脚本必须有审计日志", "修复 reviewMissingLogs 迁移脚本检测逻辑");
2303
+ }
2304
+ }
2305
+ catch (e) {
2306
+ hardFail("CODE_OBSERVABILITY_EXECUTION_ERROR", `problem-68: 可观测性行为检查执行失败: ${e.message}`, ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "契约模块必须可运行并返回确定结果", "修复运行时异常");
2307
+ }
2308
+ // 主链路消费检查 — sf_verify 必须调用 verifyChangedFilesObservability
2309
+ const toolsText = safeRead(path.join(rootDir, "src", "adapters", "claude_code", "tools.ts")) ?? "";
2310
+ const requiredHooks = [
2311
+ "lazyCodeObservability", "reviewCodeObservability",
2312
+ "hasBlockingObservabilityFindings", "requiresCodeObservabilityContract",
2313
+ "evaluateCodeObservabilityGate", "evaluateDeliveryBlock",
2314
+ "verifyChangedFilesObservability",
2315
+ ];
2316
+ for (const hook of requiredHooks) {
2317
+ if (!toolsText.includes(hook)) {
2318
+ hardFail("CODE_OBSERVABILITY_MAINPATH_MISSING", `problem-68: MCP 主链路缺少真实消费点 ${hook}`, ["src/adapters/claude_code/tools.ts"], "problem-68", "只实现引擎函数不能证明用户路径受约束", "接入 sf_expand/sf_review/sf_verify/sf_deliver");
2319
+ }
2320
+ }
2321
+ // 行为验证: sf_verify 必须真实消费 verifyChangedFilesObservability — 编译后检查
2322
+ try {
2323
+ const toolsJsPath = path.join(rootDir, "dist", "adapters", "claude_code", "tools.js");
2324
+ if (fs.existsSync(toolsJsPath)) {
2325
+ const toolsJs = safeRead(toolsJsPath) ?? "";
2326
+ const hasObsVerifyCall = toolsJs.includes("codeObservabilityFinding")
2327
+ && toolsJs.includes("verifyChangedFilesObservability");
2328
+ if (!hasObsVerifyCall) {
2329
+ hardFail("CODE_OBSERVABILITY_SF_VERIFY_NOT_CONSUMING", "problem-68: sf_verify 编译产物未包含可观测性诊断常量或 verifyChangedFilesObservability 调用", ["src/adapters/claude_code/tools.ts"], "problem-68", "字符串引用不能证明 sf_verify 真实消费可观测性检查", "在 sf_verify implementationFiles 分支中调用 verifyChangedFilesObservability 并处理结果");
2330
+ }
2331
+ }
2332
+ }
2333
+ catch {
2334
+ // 编译产物不存在时由 build 门禁处理
2335
+ }
2336
+ // 行为验证: sf_verify 必须能阻断 — 敏感信息 + 支付写操作必须产生 hard_fail
2337
+ try {
2338
+ const mustFailFindings = obs.verifyChangedFilesObservability({
2339
+ changed_files: ["PaymentService.ts"],
2340
+ file_contents: {
2341
+ "PaymentService.ts": `const api_key = "sk_live_abcdef123456";
2342
+ async function processPayment(order) { order.save(); }`,
2343
+ },
2344
+ intent: "添加支付退款日志和脱敏处理",
2345
+ });
2346
+ if (!obs.hasBlockingObservabilityFindings(mustFailFindings)) {
2347
+ hardFail("CODE_OBSERVABILITY_VERIFY_MUST_FAIL_PASS", "problem-68: sf_verify 未对敏感信息泄漏+支付无日志场景产生阻断", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "verifyChangedFilesObservability 必须对支付敏感信息场景 hard_fail", "修复 verifyChangedFilesObservability 检测逻辑");
2348
+ }
2349
+ // sf_verify 必须允许合规代码通过
2350
+ const mustPassFindings = obs.verifyChangedFilesObservability({
2351
+ changed_files: ["RefundService.ts"],
2352
+ file_contents: {
2353
+ "RefundService.ts": `const logger = require('./logger');
2354
+ async function processRefund(orderId: string) {
2355
+ await db.refund(orderId);
2356
+ logger.info("退款成功 orderId=" + orderId);
2357
+ }`,
2358
+ },
2359
+ intent: "添加支付退款日志和脱敏处理",
2360
+ });
2361
+ if (obs.hasBlockingObservabilityFindings(mustPassFindings)) {
2362
+ hardFail("CODE_OBSERVABILITY_VERIFY_FALSE_BLOCK", "problem-68: sf_verify 对合规代码错误阻断", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "合规代码不应被阻断", "修复 verifyChangedFilesObservability 检测逻辑");
2363
+ }
2364
+ // 行为验证: logger.info("退款成功") 无可定位字段必须 hard_fail
2365
+ const unlocatableFailFindings = obs.verifyChangedFilesObservability({
2366
+ changed_files: ["RefundService.ts"],
2367
+ file_contents: {
2368
+ "RefundService.ts": `const logger = require('./logger');
2369
+ async function refund(order) { order.save(); logger.info("退款成功"); }`,
2370
+ },
2371
+ intent: "添加支付退款日志和脱敏处理",
2372
+ });
2373
+ const unlocatableHardFails = unlocatableFailFindings.filter((f) => f.category === "unlocatable_log" && f.severity === "hard_fail");
2374
+ if (unlocatableHardFails.length === 0) {
2375
+ hardFail("CODE_OBSERVABILITY_UNLOCATABLE_LOG_PASS", "problem-68: logger.info('退款成功') 无可定位字段未被阻断", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "仅含事件词的日志不可通过支付写操作检查", "修复可定位字段判断逻辑");
2376
+ }
2377
+ // 行为验证: logger.info("退款成功 orderId=" + orderId) 必须通过
2378
+ const unlocatablePassFindings = obs.verifyChangedFilesObservability({
2379
+ changed_files: ["RefundService.ts"],
2380
+ file_contents: {
2381
+ "RefundService.ts": `const logger = require('./logger');
2382
+ async function refund(order) { order.save(); logger.info("退款成功 orderId=" + orderId); }`,
2383
+ },
2384
+ intent: "添加支付退款日志和脱敏处理",
2385
+ });
2386
+ const unlocatableBlockers = unlocatablePassFindings.filter((f) => f.category === "unlocatable_log" && f.severity === "hard_fail");
2387
+ if (unlocatableBlockers.length > 0) {
2388
+ hardFail("CODE_OBSERVABILITY_LOCATABLE_FALSE_BLOCK", "problem-68: logger.info('退款成功 orderId=...') 含可定位字段被错误阻断", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "包含对象 ID 的日志不应被阻断", "修复可定位字段判断逻辑");
2389
+ }
2390
+ }
2391
+ catch (e) {
2392
+ hardFail("CODE_OBSERVABILITY_VERIFY_EXECUTION_ERROR", `problem-68: sf_verify 行为检查执行失败: ${e.message}`, ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "verifyChangedFilesObservability 必须可运行并返回确定结果", "修复运行时异常");
2393
+ }
2394
+ _info(" problem-68 代码可维护性与可观测性行为验证完成");
2395
+ }
2396
+ async function checkLongTermMechanization(rootDir, hardFail, _info) {
2397
+ try {
2398
+ const health = await import("./mechanism_health_check.js");
2399
+ const report = health.runFullHealthCheck(rootDir);
2400
+ for (const finding of report.findings.filter((f) => f.severity === "hard_fail")) {
2401
+ hardFail("LONGTERM_MECHANISM_HEALTH", finding.message_zh, [finding.target], "历史问题长期机制化", "旧 gate 不检查机制死代码/未消费资产", "修复机制消费链路");
2402
+ }
2403
+ }
2404
+ catch (e) {
2405
+ hardFail("LONGTERM_MECHANISM_HEALTH_EXCEPTION", `机制运行时健康度检查异常: ${e.message}`, ["src/engine/mechanism_health_check.ts"], "历史问题长期机制化", "旧 gate 不执行机制健康检查", "修复检查模块");
2406
+ }
2407
+ try {
2408
+ const kg = await import("./knowledge_governance_gate.js");
2409
+ const report = kg.runKnowledgeGovernanceCheck({
2410
+ project_language: "zh",
2411
+ contents: [{ id: "release-gate", domain: "user_feedback", content: "发布门禁保持中文语义优先" }],
2412
+ });
2413
+ if (report.hard_fail_count > 0) {
2414
+ hardFail("LONGTERM_KNOWLEDGE_GOVERNANCE", `知识治理存在 ${report.hard_fail_count} 个 hard_fail`, ["src/engine/knowledge_governance_gate.ts"], "历史问题长期机制化", "旧 gate 只跑历史知识场景,不接统一治理入口", "修复知识治理检查");
2415
+ }
2416
+ }
2417
+ catch (e) {
2418
+ hardFail("LONGTERM_KNOWLEDGE_GOVERNANCE_EXCEPTION", `知识治理检查异常: ${e.message}`, ["src/engine/knowledge_governance_gate.ts"], "历史问题长期机制化", "旧 gate 不执行知识治理入口", "修复检查模块");
2419
+ }
2420
+ try {
2421
+ const logGov = await import("./log_governance.js");
2422
+ const clean = logGov.enforceLogGovernance("用户可见输出保持中文且无内部噪音");
2423
+ const noisy = logGov.enforceLogGovernance("[soloForge] internal trace validate-release");
2424
+ if (!clean.passed || noisy.passed) {
2425
+ hardFail("LONGTERM_LOG_GOVERNANCE_BEHAVIOR", "日志治理 must-pass/must-fail 行为不成立", ["src/engine/log_governance.ts"], "历史问题长期机制化", "旧 gate 只扫描 console,不验证输出治理行为", "修复 log_governance 行为");
2426
+ }
2427
+ }
2428
+ catch (e) {
2429
+ hardFail("LONGTERM_LOG_GOVERNANCE_EXCEPTION", `日志治理检查异常: ${e.message}`, ["src/engine/log_governance.ts"], "历史问题长期机制化", "旧 gate 不执行日志治理入口", "修复检查模块");
2430
+ }
2431
+ try {
2432
+ const cfg = await import("./config_write_boundary.js");
2433
+ const runtimeCtx = cfg.classifyConfigContext(rootDir, { runtime_inference: true });
2434
+ const runtimeDecision = cfg.isWriteAllowed(runtimeCtx, path.join(rootDir, ".soloforge", "config.yaml"));
2435
+ const greenfieldDecision = cfg.isWriteAllowed({ kind: "greenfield", project_path: rootDir, evidence: ["empty_project"], confirmed: false }, path.join(rootDir, ".soloforge", "config.yaml"));
2436
+ if (runtimeDecision.allowed || !greenfieldDecision.allowed) {
2437
+ hardFail("LONGTERM_CONFIG_BOUNDARY_BEHAVIOR", "配置落盘边界 must-pass/must-fail 行为不成立", ["src/engine/config_write_boundary.ts"], "历史问题长期机制化", "旧 gate 不区分运行时推断与空项目写入", "修复配置写入边界");
2438
+ }
2439
+ }
2440
+ catch (e) {
2441
+ hardFail("LONGTERM_CONFIG_BOUNDARY_EXCEPTION", `配置落盘边界检查异常: ${e.message}`, ["src/engine/config_write_boundary.ts"], "历史问题长期机制化", "旧 gate 不执行配置落盘边界", "修复检查模块");
2442
+ }
2443
+ _info(" 历史问题长期机制化行为验证完成");
2444
+ }
2445
+ async function checkDiagnosticCentralization(rootDir, hardFail) {
2446
+ const toolsPath = path.join(rootDir, "src", "adapters", "claude_code", "tools.ts");
2447
+ const toolsText = safeRead(toolsPath) ?? "";
2448
+ const literalMatches = [...toolsText.matchAll(/["'`]SF-[A-Z]+-\d{4}["'`]/g)];
2449
+ if (literalMatches.length > 0) {
2450
+ hardFail("DIAGNOSTIC_CODE_HARDCODED_IN_TOOLS", `tools.ts 仍有 ${literalMatches.length} 个硬编码诊断码字面量`, ["src/adapters/claude_code/tools.ts"], "problem-36", "旧 gate 不检查诊断码集中治理", "改用 diagnostic_registry 导出的 TOOL_DIAGNOSTIC_CODES");
2451
+ }
2452
+ const registry = await import("./diagnostic_registry.js");
2453
+ const required = Object.values(registry.TOOL_DIAGNOSTIC_CODES);
2454
+ const registered = new Set(registry.listAllDiagnostics().map((d) => d.code));
2455
+ const missing = required.filter((code) => !registered.has(code));
2456
+ if (missing.length > 0) {
2457
+ hardFail("DIAGNOSTIC_CODE_REGISTRY_MISSING", `诊断码常量未在注册表登记: ${missing.join(", ")}`, ["src/engine/diagnostic_registry.ts"], "problem-36", "旧 gate 不检查诊断码注册完整性", "补齐 BUILTIN_DIAGNOSTICS");
2458
+ }
2459
+ }
2220
2460
  // ── 主入口 ──
2221
2461
  export async function runReleaseReadinessGate(rootDir) {
2222
2462
  const hardFails = [];
@@ -2315,6 +2555,18 @@ export async function runReleaseReadinessGate(rootDir) {
2315
2555
  beginPhase("实现工程契约行为验证");
2316
2556
  await checkImplementationContractBehavior(rootDir, hardFail, _info);
2317
2557
  endPhase("实现工程契约行为验证");
2558
+ // 18: 代码可维护性与可观测性契约行为验证(问题六十八)
2559
+ beginPhase("代码可维护性与可观测性行为验证");
2560
+ await checkCodeObservabilityBehavior(rootDir, hardFail, _info);
2561
+ endPhase("代码可维护性与可观测性行为验证");
2562
+ // 19: 历史问题长期机制化行为验证
2563
+ beginPhase("历史问题长期机制化行为验证");
2564
+ await checkLongTermMechanization(rootDir, hardFail, _info);
2565
+ endPhase("历史问题长期机制化行为验证");
2566
+ // 20: 诊断码集中治理检查
2567
+ beginPhase("诊断码集中治理检查");
2568
+ await checkDiagnosticCentralization(rootDir, hardFail);
2569
+ endPhase("诊断码集中治理检查");
2318
2570
  // 恢复 console.error 和日志器
2319
2571
  console.error = origConsoleError;
2320
2572
  resetLogger();