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.
Files changed (141) hide show
  1. package/README.md +19 -3
  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 +164 -44
  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.d.ts.map +1 -1
  10. package/dist/bin/soloforge.js +148 -1
  11. package/dist/bin/soloforge.js.map +1 -1
  12. package/dist/engine/asset_manifest.d.ts.map +1 -1
  13. package/dist/engine/asset_manifest.js +11 -0
  14. package/dist/engine/asset_manifest.js.map +1 -1
  15. package/dist/engine/backend_implementation_contract.d.ts +1 -1
  16. package/dist/engine/backend_implementation_contract.d.ts.map +1 -1
  17. package/dist/engine/backend_implementation_contract.js +22 -0
  18. package/dist/engine/backend_implementation_contract.js.map +1 -1
  19. package/dist/engine/brainstorm_contract.d.ts +1 -1
  20. package/dist/engine/brainstorm_contract.js +1 -1
  21. package/dist/engine/code_maintainability_observability_contract.d.ts +74 -0
  22. package/dist/engine/code_maintainability_observability_contract.d.ts.map +1 -0
  23. package/dist/engine/code_maintainability_observability_contract.js +711 -0
  24. package/dist/engine/code_maintainability_observability_contract.js.map +1 -0
  25. package/dist/engine/config_write_boundary.d.ts +29 -0
  26. package/dist/engine/config_write_boundary.d.ts.map +1 -0
  27. package/dist/engine/config_write_boundary.js +69 -0
  28. package/dist/engine/config_write_boundary.js.map +1 -0
  29. package/dist/engine/consumable_asset_registry.d.ts.map +1 -1
  30. package/dist/engine/consumable_asset_registry.js +49 -1
  31. package/dist/engine/consumable_asset_registry.js.map +1 -1
  32. package/dist/engine/contract_registry.js +1 -1
  33. package/dist/engine/diagnostic_registry.d.ts +13 -0
  34. package/dist/engine/diagnostic_registry.d.ts.map +1 -1
  35. package/dist/engine/diagnostic_registry.js +68 -0
  36. package/dist/engine/diagnostic_registry.js.map +1 -1
  37. package/dist/engine/dual_layer_mechanism_registry.d.ts.map +1 -1
  38. package/dist/engine/dual_layer_mechanism_registry.js +195 -2
  39. package/dist/engine/dual_layer_mechanism_registry.js.map +1 -1
  40. package/dist/engine/explicit_asset_registry.d.ts.map +1 -1
  41. package/dist/engine/explicit_asset_registry.js +134 -0
  42. package/dist/engine/explicit_asset_registry.js.map +1 -1
  43. package/dist/engine/extension_scenario_registry.js +4 -4
  44. package/dist/engine/extension_scenario_registry.js.map +1 -1
  45. package/dist/engine/foundation_scenario_runners.d.ts.map +1 -1
  46. package/dist/engine/foundation_scenario_runners.js +4 -2
  47. package/dist/engine/foundation_scenario_runners.js.map +1 -1
  48. package/dist/engine/historical_issue_mechanization_matrix.d.ts +28 -0
  49. package/dist/engine/historical_issue_mechanization_matrix.d.ts.map +1 -0
  50. package/dist/engine/historical_issue_mechanization_matrix.js +134 -0
  51. package/dist/engine/historical_issue_mechanization_matrix.js.map +1 -0
  52. package/dist/engine/implementation_roadmap_registry.d.ts.map +1 -1
  53. package/dist/engine/implementation_roadmap_registry.js +114 -13
  54. package/dist/engine/implementation_roadmap_registry.js.map +1 -1
  55. package/dist/engine/intent_expander.d.ts.map +1 -1
  56. package/dist/engine/intent_expander.js +151 -1
  57. package/dist/engine/intent_expander.js.map +1 -1
  58. package/dist/engine/knowledge_governance_gate.d.ts +38 -0
  59. package/dist/engine/knowledge_governance_gate.d.ts.map +1 -0
  60. package/dist/engine/knowledge_governance_gate.js +123 -0
  61. package/dist/engine/knowledge_governance_gate.js.map +1 -0
  62. package/dist/engine/log_governance.d.ts +25 -0
  63. package/dist/engine/log_governance.d.ts.map +1 -0
  64. package/dist/engine/log_governance.js +76 -0
  65. package/dist/engine/log_governance.js.map +1 -0
  66. package/dist/engine/mechanism_contract_registry.d.ts +1 -0
  67. package/dist/engine/mechanism_contract_registry.d.ts.map +1 -1
  68. package/dist/engine/mechanism_contract_registry.js +104 -0
  69. package/dist/engine/mechanism_contract_registry.js.map +1 -1
  70. package/dist/engine/mechanism_health_check.d.ts +23 -0
  71. package/dist/engine/mechanism_health_check.d.ts.map +1 -0
  72. package/dist/engine/mechanism_health_check.js +140 -0
  73. package/dist/engine/mechanism_health_check.js.map +1 -0
  74. package/dist/engine/next_action_planner.d.ts.map +1 -1
  75. package/dist/engine/next_action_planner.js +72 -4
  76. package/dist/engine/next_action_planner.js.map +1 -1
  77. package/dist/engine/observability.js +1 -1
  78. package/dist/engine/observability.js.map +1 -1
  79. package/dist/engine/project_knowledge_contract.d.ts +58 -0
  80. package/dist/engine/project_knowledge_contract.d.ts.map +1 -0
  81. package/dist/engine/project_knowledge_contract.js +298 -0
  82. package/dist/engine/project_knowledge_contract.js.map +1 -0
  83. package/dist/engine/project_knowledge_system_regression_matrix.d.ts +27 -0
  84. package/dist/engine/project_knowledge_system_regression_matrix.d.ts.map +1 -0
  85. package/dist/engine/project_knowledge_system_regression_matrix.js +295 -0
  86. package/dist/engine/project_knowledge_system_regression_matrix.js.map +1 -0
  87. package/dist/engine/release_issue_scenario_registry.d.ts.map +1 -1
  88. package/dist/engine/release_issue_scenario_registry.js +506 -95
  89. package/dist/engine/release_issue_scenario_registry.js.map +1 -1
  90. package/dist/engine/release_readiness_gate.d.ts +4 -0
  91. package/dist/engine/release_readiness_gate.d.ts.map +1 -1
  92. package/dist/engine/release_readiness_gate.js +643 -12
  93. package/dist/engine/release_readiness_gate.js.map +1 -1
  94. package/dist/engine/team_awareness.js +6 -6
  95. package/dist/engine/team_awareness.js.map +1 -1
  96. package/dist/engine/technology_decision.js +5 -5
  97. package/dist/engine/technology_decision.js.map +1 -1
  98. package/dist/engine/template_asset_contract_registry.d.ts.map +1 -1
  99. package/dist/engine/template_asset_contract_registry.js +6 -5
  100. package/dist/engine/template_asset_contract_registry.js.map +1 -1
  101. package/dist/engine/verifier.js +1 -1
  102. package/dist/engine/verifier.js.map +1 -1
  103. package/dist/engine/workflow_navigation_contract.d.ts +10 -0
  104. package/dist/engine/workflow_navigation_contract.d.ts.map +1 -1
  105. package/dist/knowledge/loader.d.ts +3 -1
  106. package/dist/knowledge/loader.d.ts.map +1 -1
  107. package/dist/knowledge/loader.js +2 -2
  108. package/dist/knowledge/loader.js.map +1 -1
  109. package/dist/types.d.ts +23 -0
  110. package/dist/types.d.ts.map +1 -1
  111. package/package.json +1 -1
  112. 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
  113. 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
  114. 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
  115. package/templates/knowledge/domain//346/224/257/344/273/230/350/247/204/345/210/231.md +1 -1
  116. 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
  117. 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
  118. package/templates/knowledge/procedures//351/207/215/346/236/204/346/265/201/346/260/264/347/272/277.md +1 -1
  119. 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
  120. 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
  121. 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
  122. 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
  123. 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
  124. 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
  125. 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
  126. 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
  127. 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
  128. 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
  129. 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
  130. 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
  131. package/templates/patterns/Git/346/223/215/344/275/234/350/247/204/350/214/203.md +1 -1
  132. package/templates/scaffolds/react/Form.tsx.hbs +11 -3
  133. package/templates/scaffolds/react/List.tsx.hbs +11 -3
  134. package/templates/scaffolds/react/Page.tsx.hbs +1 -1
  135. package/templates/scaffolds/react/types.ts.hbs +4 -1
  136. package/templates/scaffolds/spring-boot/Controller.java.hbs +18 -4
  137. package/templates/scaffolds/spring-boot/DTO.java.hbs +4 -1
  138. package/templates/scaffolds/spring-boot/Entity.java.hbs +8 -3
  139. package/templates/scaffolds/spring-boot/Mapper.java.hbs +4 -1
  140. package/templates/scaffolds/spring-boot/ServiceImpl.java.hbs +34 -10
  141. package/templates/scaffolds/spring-boot/ServiceTest.java.hbs +0 -1
@@ -21,6 +21,10 @@
21
21
  * 13. 第五批一致性校验
22
22
  * 14. 依赖漏洞扫描
23
23
  * 15. 发布问题架构决策与设计产物真实消费
24
+ * 18. 代码可维护性与可观测性契约行为验证
25
+ * 19. 历史问题长期机制化行为验证
26
+ * 20. 诊断码集中治理检查
27
+ * 21. 模板卫生与项目知识消费验证
24
28
  */
25
29
  import fs from "node:fs";
26
30
  import os from "node:os";
@@ -619,7 +623,12 @@ function checkTestPollution(rootDir, hardFail, _info) {
619
623
  const checksImplementedVerified = content.includes("implemented_verified");
620
624
  const checksFileExists = /existsSync/.test(content) && /required.*file/i.test(content);
621
625
  const checksScenarioSelfAttest = /fixture_status.*ready|scenario.*status.*PASS/.test(content);
622
- if (isScenarioMatrix) {
626
+ const hasPlaceholderTest = /场景注册占位/.test(content) || /expect\s*\(\s*true\s*\)\s*\.\s*toBe\s*\(\s*true\s*\)/.test(content) || /registered\s+only/.test(content);
627
+ const hasTodoPlaceholder = /\bit\s*\.\s*todo\s*\(/.test(content) || /\bdescribe\s*\.\s*todo\s*\(/.test(content);
628
+ if (hasPlaceholderTest || hasTodoPlaceholder) {
629
+ categories.suspicious_test_pollution.push(rel);
630
+ }
631
+ else if (isScenarioMatrix) {
623
632
  categories.batch_construction_test.push(rel);
624
633
  }
625
634
  else if (usefulContractExemptions.has(rel)) {
@@ -1124,26 +1133,30 @@ async function checkBatchIssueFormatConsistency(rootDir, hardFail, _info) {
1124
1133
  // 复用 scripts/batch_issue_details.mjs 的共享解析逻辑,不维护独立的问题识别规则
1125
1134
  const scriptPath = path.join(rootDir, "scripts", "batch_issue_details.mjs");
1126
1135
  let loadBatchIssueDetails;
1136
+ let validateCanonicalIssueLedger;
1127
1137
  try {
1128
1138
  const mod = await import(scriptPath);
1129
1139
  loadBatchIssueDetails = mod.loadBatchIssueDetails;
1140
+ validateCanonicalIssueLedger = mod.validateCanonicalIssueLedger;
1130
1141
  }
1131
1142
  catch (e) {
1132
1143
  hardFail("BATCH_ISSUE_FORMAT_INCONSISTENT", `无法加载共享解析脚本: ${e.message}`, ["scripts/batch_issue_details.mjs"], "构建系统", "共享解析脚本不可用", "修复脚本");
1133
1144
  return;
1134
1145
  }
1135
- if (!loadBatchIssueDetails) {
1136
- hardFail("BATCH_ISSUE_FORMAT_INCONSISTENT", "loadBatchIssueDetails 导出未找到", ["scripts/batch_issue_details.mjs"], "构建系统", "共享解析脚本导出不正确", "修复脚本");
1146
+ if (!loadBatchIssueDetails || !validateCanonicalIssueLedger) {
1147
+ hardFail("BATCH_ISSUE_FORMAT_INCONSISTENT", "共享解析脚本缺少 Batch 加载或 canonical ledger 校验导出", ["scripts/batch_issue_details.mjs"], "构建系统", "共享解析脚本导出不正确", "修复脚本");
1137
1148
  return;
1138
1149
  }
1139
- const expectedCounts = { 1: 19, 2: 12, 3: 9, 4: 13, 5: 6, 6: 5, 7: 2 };
1150
+ const expectedCounts = { 1: 19, 2: 12, 3: 9, 4: 14, 5: 6, 6: 5, 7: 2, 8: 4 };
1151
+ const parsedBatches = [];
1140
1152
  const requiredPerProblemSections = [
1141
1153
  "问题背景", "用户反馈 / 触发场景", "根因分析", "解决方案", "方案细节",
1142
1154
  "硬规则", "非目标", "影响范围", "落地文件", "验收标准", "回归风险",
1143
1155
  "与其他问题的关联", "发布门禁要求",
1144
1156
  ];
1145
- for (let batch = 1; batch <= 7; batch++) {
1157
+ for (let batch = 1; batch <= 8; batch++) {
1146
1158
  const details = loadBatchIssueDetails(batch, rootDir);
1159
+ parsedBatches.push(details);
1147
1160
  if (!details.loaded) {
1148
1161
  hardFail("BATCH_ISSUE_FORMAT_INCONSISTENT", `Batch${batch} 问题集未加载: ${details.error}`, [`docs/SoloForge-Batch${batch}问题集.md`], `Batch${batch}`, "旧 gate 只检查文档存在,不验证是否可解析", "第 3 步统一格式");
1149
1162
  continue;
@@ -1187,7 +1200,27 @@ async function checkBatchIssueFormatConsistency(rootDir, hardFail, _info) {
1187
1200
  }
1188
1201
  _info(` Batch${batch}: 已检查 (${details.issue_count} 个问题)`);
1189
1202
  }
1190
- _info(" 说明: 本检查不修改文档。格式不一致问题将在第 3 步统一处理。");
1203
+ try {
1204
+ const roadmapPath = path.join(rootDir, "dist", "engine", "implementation_roadmap_registry.js");
1205
+ const roadmap = await import(roadmapPath);
1206
+ const roadmapProblems = roadmap.listAllProblems();
1207
+ const ledgerFindings = validateCanonicalIssueLedger(parsedBatches, roadmapProblems, 71);
1208
+ for (const finding of ledgerFindings) {
1209
+ 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
+ const roadmapFindings = roadmap.validateImplementationRoadmap()
1212
+ .filter((finding) => finding.severity === "hard_fail");
1213
+ for (const finding of roadmapFindings) {
1214
+ hardFail("CANONICAL_ISSUE_LEDGER_INCONSISTENT", finding.message, ["src/engine/implementation_roadmap_registry.ts"], finding.subject_id ?? "roadmap", "旧 gate 不执行 roadmap 内部双向引用校验", "修正 ProblemEntry 与 ImplementationBatch 的双向归属");
1215
+ }
1216
+ if (ledgerFindings.length === 0 && roadmapFindings.length === 0) {
1217
+ _info(" canonical ledger: 问题文档与 roadmap 的 71 个问题身份、归属一致");
1218
+ }
1219
+ }
1220
+ catch (e) {
1221
+ hardFail("CANONICAL_ISSUE_LEDGER_INCONSISTENT", `无法执行 canonical 问题账本对账: ${e.message}`, ["scripts/batch_issue_details.mjs", "src/engine/implementation_roadmap_registry.ts"], "canonical-ledger", "旧 gate 不加载 roadmap 执行文档双向对账", "先完成 build 并修复账本校验入口");
1222
+ }
1223
+ _info(" 说明: 本检查不修改文档;格式或 canonical 身份不一致会阻断发布。");
1191
1224
  }
1192
1225
  // ── 机制身份一致性 ──
1193
1226
  async function checkMechanismIdentityConsistency(rootDir, hardFail, _info) {
@@ -1341,7 +1374,7 @@ async function checkKnowledgeAssetSchema(rootDir, hardFail, _info) {
1341
1374
  }
1342
1375
  }
1343
1376
  }
1344
- // ── Phase 11: engine console.log 检查 ──
1377
+ // ── Phase 11: engine console 直写检查 ──
1345
1378
  function checkEngineConsoleLog(rootDir, hardFail) {
1346
1379
  // 扫描全 src/ 目录(不仅 engine)
1347
1380
  const srcDir = path.join(rootDir, "src");
@@ -1359,12 +1392,13 @@ function checkEngineConsoleLog(rootDir, hardFail) {
1359
1392
  continue;
1360
1393
  if (/"console\.log"|`console\.log`|'console\.log'|console\\.log/.test(line))
1361
1394
  continue;
1362
- // 日志模块内部 stdout 封装允许 console.log
1363
- if (/logger\.ts$/.test(file) && /^\s*console\.log\(/.test(line))
1395
+ // 日志模块内部 stdout/stderr 封装允许 console.log / console.error
1396
+ if (/logger\.ts$/.test(file) && /^\s*console\.(log|error)\(/.test(line))
1364
1397
  continue;
1365
- if (/console\.log\s*\(/.test(line)) {
1398
+ const directConsole = line.match(/console\.(log|warn|error|debug)\s*\(/);
1399
+ if (directConsole) {
1366
1400
  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 模块调用");
1401
+ hardFail("ENGINE_DIRECT_CONSOLE", `${rel}:${i + 1} 使用 console.${directConsole[1]}(应使用 logger 模块)`, [rel], "发布门禁 console 检查", "旧 gate 不检查 src/ 全目录 console 直写", "替换为 logger 模块调用");
1368
1402
  }
1369
1403
  }
1370
1404
  }
@@ -1629,6 +1663,14 @@ async function checkImplementationContractBehavior(rootDir, hardFail, _info) {
1629
1663
  if (!backend.hasBlockingBackendFindings(alignmentFindings)) {
1630
1664
  hardFail("BACKEND_API_OPENAPI_DRIFT_FALSE_PASS", "problem-67: Markdown API 与 OpenAPI endpoint 漂移未阻断", ["src/engine/backend_implementation_contract.ts"], "problem-67", "契约对齐必须由行为检查证明", "修复 API/OpenAPI 漂移检测");
1631
1665
  }
1666
+ const lombokFindings = backend.reviewBackendImplementationFiles({
1667
+ "src/main/java/com/smartcare/staff/entity/Staff.java": "import jakarta.persistence.Entity; import lombok.Data; @Entity @Data public class Staff { private Long id; }",
1668
+ "src/main/java/com/smartcare/staff/dto/StaffCreateRequest.java": "import lombok.Getter; import lombok.Setter; @Getter @Setter public class StaffCreateRequest { private String name; }",
1669
+ });
1670
+ const modelContractFindings = lombokFindings.filter((item) => item.category === "model_lombok_contract" && item.severity === "hard_fail");
1671
+ if (modelContractFindings.length < 2) {
1672
+ hardFail("BACKEND_MODEL_LOMBOK_CONTRACT_FALSE_PASS", "problem-71: Java Entity/DTO/VO/Request Lombok 分层契约未阻断错误注解", ["src/engine/backend_implementation_contract.ts", "templates/scaffolds/spring-boot/Entity.java.hbs", "templates/scaffolds/spring-boot/DTO.java.hbs"], "problem-71", "后端工程契约不能只治理 Controller/DTO 命名,还必须约束数据模型注解语义", "添加 Entity @Getter/@Setter、DTO/VO/Request @Data 的行为检查和脚手架默认值");
1673
+ }
1632
1674
  }
1633
1675
  catch (e) {
1634
1676
  hardFail("IMPLEMENTATION_CONTRACT_EXECUTION_ERROR", `problem-66/67: 实现工程行为检查执行失败: ${e.message}`, ["src/engine/ood_solid_contract.ts", "src/engine/backend_implementation_contract.ts"], "problem-66/problem-67", "契约模块必须可运行并返回确定结果", "修复运行时异常");
@@ -1680,11 +1722,43 @@ async function checkReleaseIssueDesignPath(rootDir, hardFail, _info) {
1680
1722
  if (noTrace.length > 0) {
1681
1723
  hardFail("RELEASE_ISSUE_SCENARIO_NO_PRODUCTION_TRACE", `场景缺少 production_trace: ${noTrace.map(r => r.scenario_id).join("; ")}`, ["src/engine/release_issue_scenario_registry.ts"], "release-issues", "所有场景必须有 production_trace 记录真实入口", "为缺失场景添加 production_trace");
1682
1724
  }
1725
+ // R10.1: 每个场景(非 engine_contract 声明)的 tool_entrypoint 必须包含真实工具名
1726
+ const allRealToolNames = ["sf_classify", "sf_expand", "sf_verify", "sf_deliver", "sf_learn", "sf_accept", "sf_record_verification_execution", "sf_scaffold", "sf_navigation", "soloforge next", "checkArchitectureDecisionWorkshopGate", "planNextAction"];
1727
+ const fakeTraceScenarios = execResults.filter(r => r.production_trace &&
1728
+ !allRealToolNames.some(t => r.production_trace.tool_entrypoint.includes(t)) &&
1729
+ !r.production_trace.gates_consumed?.includes("engine_contract"));
1730
+ if (fakeTraceScenarios.length > 0) {
1731
+ hardFail("RELEASE_ISSUE_SCENARIO_NO_PRODUCTION_TRACE", `场景 production_trace 不引用真实工具入口: ${fakeTraceScenarios.map(r => `${r.scenario_id}(entrypoint=${r.production_trace.tool_entrypoint})`).join("; ")}`, ["src/engine/release_issue_scenario_registry.ts"], "release-issues", "所有场景的 production_trace.tool_entrypoint 必须引用真实工具(sf_classify/sf_expand/adapter gate 等)", "用 createToolHarness 重写 runner");
1732
+ }
1683
1733
  // R12: production_trace 的 diagnostic_codes 必须非空(来自工具返回值或函数调用结果)
1684
1734
  const noDiagCodes = execResults.filter(r => r.production_trace && (!r.production_trace.diagnostic_codes || r.production_trace.diagnostic_codes.length === 0));
1685
1735
  if (noDiagCodes.length > 0) {
1686
1736
  hardFail("RELEASE_ISSUE_SCENARIO_NO_PRODUCTION_TRACE", `场景 production_trace 缺少 diagnostic_codes: ${noDiagCodes.map(r => r.scenario_id).join("; ")}`, ["src/engine/release_issue_scenario_registry.ts"], "release-issues", "所有 production_trace 必须包含来自工具/函数返回值的 diagnostic_codes", "为场景添加真实 diagnostic_codes");
1687
1737
  }
1738
+ // R14: architecture-workshop 非 low-risk 场景必须真正触发 workshop(不得假绿)
1739
+ {
1740
+ const archNonLowRisk = execResults.filter(r => r.scenario_id.startsWith("release-scenario-architecture-workshop-") &&
1741
+ !r.scenario_id.includes("low-risk-skip"));
1742
+ const fakeGreenPatterns = ["workshop=false", "domains=0", "no workshop", "blocked by earlier gate"];
1743
+ const fakeGreens = archNonLowRisk.filter(r => r.status === "pass" && fakeGreenPatterns.some(p => r.evidence?.includes(p)));
1744
+ if (fakeGreens.length > 0) {
1745
+ hardFail("RELEASE_ISSUE_SCENARIO_NO_PRODUCTION_TRACE", `architecture-workshop 场景假绿: ${fakeGreens.map(r => `${r.scenario_id}(evidence=${r.evidence?.slice(0, 120)})`).join("; ")}`, ["src/engine/release_issue_scenario_registry.ts"], "release-issues", "非 low-risk 架构研讨场景必须真正触发 architecture_decision_workshop,不得把证据门阻断当作 pass", "确保场景提供足够证据通过 evidence grounding gate,使 workshop gate 能实际触发");
1746
+ }
1747
+ // 非 low-risk 场景必须同时有 sf_classify 和 sf_expand 入口
1748
+ const missingEntrypoint = archNonLowRisk.filter(r => r.production_trace &&
1749
+ (!r.production_trace.tool_entrypoint.includes("sf_classify") || !r.production_trace.tool_entrypoint.includes("sf_expand")));
1750
+ if (missingEntrypoint.length > 0) {
1751
+ hardFail("RELEASE_ISSUE_SCENARIO_NO_PRODUCTION_TRACE", `architecture-workshop 场景缺少 sf_classify 或 sf_expand 入口: ${missingEntrypoint.map(r => `${r.scenario_id}(entrypoint=${r.production_trace.tool_entrypoint})`).join("; ")}`, ["src/engine/release_issue_scenario_registry.ts"], "release-issues", "architecture-workshop 非 low-risk 场景必须同时通过 sf_classify 和 sf_expand 真实 MCP 工具执行", "使用 createToolHarness + callTool('sf_classify') + callTool('sf_expand') 重写 runner");
1752
+ }
1753
+ }
1754
+ // R15: production_trace.diagnostic_codes 不得包含运行时异常
1755
+ {
1756
+ const runtimeErrorPattern = /Cannot read|TypeError|ReferenceError|^undefined$|uncaught exception|\.error\b/i;
1757
+ const runtimeDiagCodes = execResults.filter(r => r.production_trace?.diagnostic_codes?.some(c => runtimeErrorPattern.test(c)));
1758
+ if (runtimeDiagCodes.length > 0) {
1759
+ hardFail("RELEASE_ISSUE_SCENARIO_DIAGNOSTIC_SWALLOWED_ERROR", `场景 production_trace.diagnostic_codes 包含运行时异常(不是业务/门禁诊断码): ${runtimeDiagCodes.map(r => `${r.scenario_id}(codes=${r.production_trace.diagnostic_codes.filter(c => runtimeErrorPattern.test(c)).join("; ")})`).join("; ")}`, ["src/engine/release_issue_scenario_registry.ts"], "release-issues", "diagnostic_codes 必须来自真实业务/门禁诊断,不得把异常信息当作有效诊断码", "定位异常根因并修复,或确保场景提供完整输入使工具不抛异常");
1760
+ }
1761
+ }
1688
1762
  // R10: 每个 problem 必须至少有一个场景通过真实 MCP 工具入口执行
1689
1763
  const realToolNames = ["sf_classify", "sf_expand", "sf_verify", "sf_deliver", "sf_learn", "sf_accept", "sf_record_verification_execution", "sf_scaffold"];
1690
1764
  // 用 scenario_id 前缀识别 problem 归属
@@ -1693,6 +1767,7 @@ async function checkReleaseIssueDesignPath(rootDir, hardFail, _info) {
1693
1767
  "problem-62": ["release-scenario-design-pack-"],
1694
1768
  "problem-63": ["release-scenario-template-contract-"],
1695
1769
  "problem-64": ["release-scenario-template-visibility-"],
1770
+ "problem-68": ["release-scenario-code-observability-"],
1696
1771
  };
1697
1772
  for (const [problem, prefixes] of Object.entries(problemPrefixes)) {
1698
1773
  const problemScenarios = execResults.filter(r => prefixes.some(p => r.scenario_id.startsWith(p)));
@@ -1988,7 +2063,7 @@ async function checkReleaseIssueDesignPath(rootDir, hardFail, _info) {
1988
2063
  hardFail("RELEASE_ISSUE_CONTRACT_MISSING", "问题六十三缺少模板契约匹配、产物验证或修复重验函数", ["src/engine/standard_asset_contract.ts"], "problem-63", "缺少核心函数不能实现契约验证", "实现 matchTemplateContract / verifyOutputAgainstContract / createRepairReverifyDirective");
1989
2064
  }
1990
2065
  // sf_verify 必须按文件逐一匹配契约(不得使用 changed_files[0] 的契约校验全部文件)
1991
- if (!toolsText.includes("lazyStandardAssetContract") || !toolsText.includes("SF-CONTRACT-0003") || !toolsText.includes("repair_reverify_directive")) {
2066
+ if (!toolsText.includes("lazyStandardAssetContract") || !toolsText.includes("TOOL_DIAGNOSTIC_CODES.contractDraft") || !toolsText.includes("repair_reverify_directive")) {
1992
2067
  hardFail("RELEASE_ISSUE_CONTRACT_MAINLINE_MISSING", "问题六十三未接入 sf_verify 模板契约验证和 sf_deliver 修复重验阻断", ["src/adapters/claude_code/tools.ts"], "problem-63", "仅有契约定义不能阻断交付", "在 sf_verify 消费模板契约验证、sf_deliver 消费修复重验阻断");
1993
2068
  }
1994
2069
  // 必须检查 per-file 匹配(不得 changed_files[0] 统一匹配)
@@ -2217,6 +2292,546 @@ async function checkReleaseIssueDesignPath(rootDir, hardFail, _info) {
2217
2292
  }
2218
2293
  }
2219
2294
  }
2295
+ // ── 18. 代码可维护性与可观测性契约行为验证(问题六十八) ──
2296
+ async function checkCodeObservabilityBehavior(rootDir, hardFail, _info) {
2297
+ const obsPath = path.join(rootDir, "dist", "engine", "code_maintainability_observability_contract.js");
2298
+ if (!fs.existsSync(obsPath)) {
2299
+ 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 并编译");
2300
+ return;
2301
+ }
2302
+ let obs;
2303
+ try {
2304
+ obs = await import(obsPath);
2305
+ }
2306
+ catch (e) {
2307
+ hardFail("CODE_OBSERVABILITY_IMPORT_ERROR", `problem-68: code_maintainability_observability_contract 导入失败: ${e.message}`, ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "可观测性模块存在但不可导入", "修复导入错误");
2308
+ return;
2309
+ }
2310
+ // 核心导出存在性
2311
+ const requiredExports = ["reviewMissingLogs", "detectSensitiveLogs", "reviewCommentQuality", "hasBlockingObservabilityFindings", "requiresCodeObservabilityContract", "isLowRiskChange", "detectProjectLogger", "verifyChangedFilesObservability", "evaluateDeliveryBlock"];
2312
+ for (const exp of requiredExports) {
2313
+ if (typeof obs[exp] !== "function") {
2314
+ hardFail("CODE_OBSERVABILITY_EXPORT_MISSING", `problem-68: code_maintainability_observability_contract.ts 缺少导出函数: ${exp}`, ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "可观测性模块缺少核心导出", `添加 ${exp} 导出`);
2315
+ }
2316
+ }
2317
+ // 行为验证: 支付写操作无日志必须被检测
2318
+ try {
2319
+ const paymentFindings = obs.reviewMissingLogs({
2320
+ "PaymentService.java": `public void refund(String orderId, BigDecimal amount) {
2321
+ orderRepository.save(order);
2322
+ paymentGateway.refund(orderId, amount);
2323
+ }`,
2324
+ });
2325
+ if (!obs.hasBlockingObservabilityFindings(paymentFindings)) {
2326
+ hardFail("CODE_OBSERVABILITY_PAYMENT_FALSE_PASS", "problem-68: 支付写操作无日志未被检测到", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "文件存在不能证明审查能力有效", "修复 reviewMissingLogs 检测逻辑");
2327
+ }
2328
+ // 行为验证: catch 吞异常无日志必须被检测
2329
+ const catchFindings = obs.reviewMissingLogs({
2330
+ "OrderService.ts": `async processOrder(orderId: string) {
2331
+ try {
2332
+ await this.client.submit(orderId);
2333
+ } catch (e) {
2334
+ return false;
2335
+ }
2336
+ }`,
2337
+ });
2338
+ if (!obs.hasBlockingObservabilityFindings(catchFindings)) {
2339
+ hardFail("CODE_OBSERVABILITY_CATCH_FALSE_PASS", "problem-68: catch 吞异常无日志未被检测到", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "catch 吞异常必须产生阻断 finding", "修复 reviewMissingLogs 检测逻辑");
2340
+ }
2341
+ // 行为验证: 敏感信息日志泄漏必须被检测
2342
+ const sensitiveFindings = obs.detectSensitiveLogs({
2343
+ "UserService.ts": `function login(user) {
2344
+ logger.info("user login", { token: "eyJhbGciOiJIUzI1NiJ9.xxxxx", password: user.password, phone: "13812345678" });
2345
+ }`,
2346
+ });
2347
+ if (!obs.hasBlockingObservabilityFindings(sensitiveFindings)) {
2348
+ hardFail("CODE_OBSERVABILITY_SENSITIVE_FALSE_PASS", "problem-68: 敏感信息日志泄漏未被检测到", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "token/password/手机号泄漏必须被阻断", "修复 detectSensitiveLogs 检测逻辑");
2349
+ }
2350
+ // 行为验证: 低风险任务不应触发
2351
+ const notTriggered = !obs.requiresCodeObservabilityContract("修复 README 错别字", "code_change");
2352
+ if (!notTriggered) {
2353
+ hardFail("CODE_OBSERVABILITY_LOW_RISK_OVERBLOCK", "problem-68: 低风险文案任务错误触发可观测性检查", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "低风险任务不应触发检查", "修复 requiresCodeObservabilityContract 判断逻辑");
2354
+ }
2355
+ // 行为验证: 项目 logger 类型检测
2356
+ const javaLogger = obs.detectProjectLogger({
2357
+ "Application.java": "import org.slf4j.LoggerFactory; private static final Logger log = LoggerFactory.getLogger(App.class);",
2358
+ });
2359
+ if (javaLogger.type !== "slf4j") {
2360
+ hardFail("CODE_OBSERVABILITY_LOGGER_DETECT_FAIL", `problem-68: SLF4J logger 未被正确识别 (got: ${javaLogger.type})`, ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "项目 logger 类型检测必须准确", "修复 detectProjectLogger 逻辑");
2361
+ }
2362
+ // 行为验证: 迁移脚本无审计日志必须被检测
2363
+ const migrationFindings = obs.reviewMissingLogs({
2364
+ "scripts/data_fix_order_status.ts": `async function migrateOrderStatus() {
2365
+ const orders = await db.query("SELECT * FROM orders WHERE status IS NULL");
2366
+ for (const order of orders) {
2367
+ await db.update("UPDATE orders SET status = 'pending' WHERE id = ?", [order.id]);
2368
+ }
2369
+ }`,
2370
+ });
2371
+ if (!obs.hasBlockingObservabilityFindings(migrationFindings)) {
2372
+ hardFail("CODE_OBSERVABILITY_MIGRATION_FALSE_PASS", "problem-68: 迁移脚本无审计日志未被检测到", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "数据修复脚本必须有审计日志", "修复 reviewMissingLogs 迁移脚本检测逻辑");
2373
+ }
2374
+ // 行为验证: 普通 Spring 后端 Slice 的 CRUD/事务双写无日志无注释也必须被检测。
2375
+ const smartCareSliceFindings = obs.verifyChangedFilesObservability({
2376
+ changed_files: ["src/main/java/com/smartcare/staff/service/impl/StaffServiceImpl.java"],
2377
+ file_contents: {
2378
+ "src/main/java/com/smartcare/staff/service/impl/StaffServiceImpl.java": `@Service
2379
+ public class StaffServiceImpl implements StaffService {
2380
+ @Transactional
2381
+ public StaffVO create(StaffCreateRequest request) {
2382
+ Staff staff = convert(request);
2383
+ staffMapper.insert(staff);
2384
+ SysUser user = buildUser(request);
2385
+ sysUserMapper.insert(user);
2386
+ return toVO(staff);
2387
+ }
2388
+ @Transactional
2389
+ public void resign(Long staffId) {
2390
+ staffMapper.updateStatus(staffId, StaffStatus.RESIGNED);
2391
+ sysUserMapper.updateAccountStatus(staffId, 0);
2392
+ }
2393
+ }`,
2394
+ },
2395
+ intent: "完成 Slice 2 机构设施与员工管理后端实现",
2396
+ });
2397
+ const smartCareBlocked = smartCareSliceFindings.some((f) => f.category === "missing_log_business_write" && f.severity === "hard_fail")
2398
+ && smartCareSliceFindings.some((f) => f.category === "missing_comment_complex");
2399
+ if (!smartCareBlocked) {
2400
+ hardFail("CODE_OBSERVABILITY_BACKEND_SLICE_FALSE_PASS", "problem-68: 普通后端 Slice 的 Controller/Service 事务双写和级联规则无日志无注释未被阻断", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "旧门禁只覆盖支付/安全/迁移,真实 CRUD 后端实现仍可无日志无注释通过", "扩展后端实现文件检测,覆盖 Controller/Service/DTO/Entity");
2401
+ }
2402
+ const javaDocAndChineseFindings = obs.verifyChangedFilesObservability({
2403
+ changed_files: ["src/main/java/com/smartcare/staff/service/impl/StaffServiceImpl.java"],
2404
+ file_contents: {
2405
+ "src/main/java/com/smartcare/staff/service/impl/StaffServiceImpl.java": `@Service
2406
+ public class StaffServiceImpl implements StaffService {
2407
+ public StaffVO create(StaffCreateRequest request) {
2408
+ Staff staff = convert(request);
2409
+ staffMapper.insert(staff);
2410
+ logger.info("staff created staffId=" + staff.getId());
2411
+ return toVO(staff);
2412
+ }
2413
+ }`,
2414
+ },
2415
+ intent: "完成 Slice 2 员工管理后端实现",
2416
+ });
2417
+ const javaDocAndChineseBlocked = ["missing_class_doc", "missing_method_doc", "missing_important_line_comment", "non_chinese_log"].every((category) => javaDocAndChineseFindings.some((f) => f.category === category && f.severity === "hard_fail"));
2418
+ if (!javaDocAndChineseBlocked) {
2419
+ hardFail("CODE_OBSERVABILITY_CHINESE_DOC_CONTRACT_FALSE_PASS", "problem-68: 后端类/方法中文 Javadoc、关键行中文注释或中文日志缺失未被阻断", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "只检查是否有日志/注释会放过英文日志、无类说明、无方法入参出参说明和关键行业务意图缺失", "扩展 reviewCommentQuality/reviewMissingLogs,强制中文日志、中文注释、类 Javadoc、方法 Javadoc 和关键行注释");
2420
+ }
2421
+ const crossStackFindings = obs.verifyChangedFilesObservability({
2422
+ changed_files: ["src/routes/staff.route.ts", "app/api/staff.py", "src/pages/StaffForm.tsx"],
2423
+ file_contents: {
2424
+ "src/routes/staff.route.ts": `router.post('/staff', async (req, res) => {
2425
+ const staff = await staffRepo.create(req.body);
2426
+ await userRepo.create({ staffId: staff.id });
2427
+ res.json(staff);
2428
+ });`,
2429
+ "app/api/staff.py": `@router.post("/staff")
2430
+ async def create_staff(payload: StaffCreate):
2431
+ staff = await staff_repo.create(payload)
2432
+ await user_repo.create(staff_id=staff.id)
2433
+ return staff`,
2434
+ "src/pages/StaffForm.tsx": `export function StaffForm() {
2435
+ async function handleSubmit(values) {
2436
+ await apiClient.post('/api/institution/staff', values);
2437
+ setStatus('created');
2438
+ }
2439
+ return <form onSubmit={handleSubmit}>...</form>;
2440
+ }`,
2441
+ },
2442
+ intent: "实现员工新增前后端接口与表单",
2443
+ });
2444
+ const crossStackBlocked = crossStackFindings.filter((f) => f.category === "missing_log_business_write" && f.severity === "hard_fail").length >= 3;
2445
+ if (!crossStackBlocked) {
2446
+ hardFail("CODE_OBSERVABILITY_CROSS_STACK_FALSE_PASS", "problem-68: 非 Spring 后端或前端业务写操作无日志/埋点未被阻断", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "问题六十八不能只覆盖 Spring 后端文件", "扩展检测到 Nest/Express/FastAPI/Go/React/Vue 等通用实现形态");
2447
+ }
2448
+ }
2449
+ catch (e) {
2450
+ hardFail("CODE_OBSERVABILITY_EXECUTION_ERROR", `problem-68: 可观测性行为检查执行失败: ${e.message}`, ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "契约模块必须可运行并返回确定结果", "修复运行时异常");
2451
+ }
2452
+ // 主链路消费检查 — sf_verify 必须调用 verifyChangedFilesObservability
2453
+ const toolsText = safeRead(path.join(rootDir, "src", "adapters", "claude_code", "tools.ts")) ?? "";
2454
+ const requiredHooks = [
2455
+ "lazyCodeObservability", "reviewCodeObservability",
2456
+ "hasBlockingObservabilityFindings", "requiresCodeObservabilityContract",
2457
+ "evaluateCodeObservabilityGate", "evaluateDeliveryBlock",
2458
+ "verifyChangedFilesObservability",
2459
+ ];
2460
+ for (const hook of requiredHooks) {
2461
+ if (!toolsText.includes(hook)) {
2462
+ 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");
2463
+ }
2464
+ }
2465
+ // 行为验证: sf_verify 必须真实消费 verifyChangedFilesObservability — 编译后检查
2466
+ try {
2467
+ const toolsJsPath = path.join(rootDir, "dist", "adapters", "claude_code", "tools.js");
2468
+ if (fs.existsSync(toolsJsPath)) {
2469
+ const toolsJs = safeRead(toolsJsPath) ?? "";
2470
+ const hasObsVerifyCall = toolsJs.includes("codeObservabilityFinding")
2471
+ && toolsJs.includes("verifyChangedFilesObservability");
2472
+ if (!hasObsVerifyCall) {
2473
+ 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 并处理结果");
2474
+ }
2475
+ }
2476
+ }
2477
+ catch {
2478
+ // 编译产物不存在时由 build 门禁处理
2479
+ }
2480
+ // 行为验证: sf_verify 必须能阻断 — 敏感信息 + 支付写操作必须产生 hard_fail
2481
+ try {
2482
+ const mustFailFindings = obs.verifyChangedFilesObservability({
2483
+ changed_files: ["PaymentService.ts"],
2484
+ file_contents: {
2485
+ "PaymentService.ts": `const api_key = "sk_live_abcdef123456";
2486
+ async function processPayment(order) { order.save(); }`,
2487
+ },
2488
+ intent: "添加支付退款日志和脱敏处理",
2489
+ });
2490
+ if (!obs.hasBlockingObservabilityFindings(mustFailFindings)) {
2491
+ hardFail("CODE_OBSERVABILITY_VERIFY_MUST_FAIL_PASS", "problem-68: sf_verify 未对敏感信息泄漏+支付无日志场景产生阻断", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "verifyChangedFilesObservability 必须对支付敏感信息场景 hard_fail", "修复 verifyChangedFilesObservability 检测逻辑");
2492
+ }
2493
+ // sf_verify 必须允许合规代码通过
2494
+ const mustPassFindings = obs.verifyChangedFilesObservability({
2495
+ changed_files: ["RefundService.ts"],
2496
+ file_contents: {
2497
+ "RefundService.ts": `const logger = require('./logger');
2498
+ async function processRefund(orderId: string) {
2499
+ await db.refund(orderId);
2500
+ logger.info("退款成功 orderId=" + orderId);
2501
+ }`,
2502
+ },
2503
+ intent: "添加支付退款日志和脱敏处理",
2504
+ });
2505
+ if (obs.hasBlockingObservabilityFindings(mustPassFindings)) {
2506
+ hardFail("CODE_OBSERVABILITY_VERIFY_FALSE_BLOCK", "problem-68: sf_verify 对合规代码错误阻断", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "合规代码不应被阻断", "修复 verifyChangedFilesObservability 检测逻辑");
2507
+ }
2508
+ // 行为验证: logger.info("退款成功") 无可定位字段必须 hard_fail
2509
+ const unlocatableFailFindings = obs.verifyChangedFilesObservability({
2510
+ changed_files: ["RefundService.ts"],
2511
+ file_contents: {
2512
+ "RefundService.ts": `const logger = require('./logger');
2513
+ async function refund(order) { order.save(); logger.info("退款成功"); }`,
2514
+ },
2515
+ intent: "添加支付退款日志和脱敏处理",
2516
+ });
2517
+ const unlocatableHardFails = unlocatableFailFindings.filter((f) => f.category === "unlocatable_log" && f.severity === "hard_fail");
2518
+ if (unlocatableHardFails.length === 0) {
2519
+ hardFail("CODE_OBSERVABILITY_UNLOCATABLE_LOG_PASS", "problem-68: logger.info('退款成功') 无可定位字段未被阻断", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "仅含事件词的日志不可通过支付写操作检查", "修复可定位字段判断逻辑");
2520
+ }
2521
+ // 行为验证: logger.info("退款成功 orderId=" + orderId) 必须通过
2522
+ const unlocatablePassFindings = obs.verifyChangedFilesObservability({
2523
+ changed_files: ["RefundService.ts"],
2524
+ file_contents: {
2525
+ "RefundService.ts": `const logger = require('./logger');
2526
+ async function refund(order) { order.save(); logger.info("退款成功 orderId=" + orderId); }`,
2527
+ },
2528
+ intent: "添加支付退款日志和脱敏处理",
2529
+ });
2530
+ const unlocatableBlockers = unlocatablePassFindings.filter((f) => f.category === "unlocatable_log" && f.severity === "hard_fail");
2531
+ if (unlocatableBlockers.length > 0) {
2532
+ hardFail("CODE_OBSERVABILITY_LOCATABLE_FALSE_BLOCK", "problem-68: logger.info('退款成功 orderId=...') 含可定位字段被错误阻断", ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "包含对象 ID 的日志不应被阻断", "修复可定位字段判断逻辑");
2533
+ }
2534
+ }
2535
+ catch (e) {
2536
+ hardFail("CODE_OBSERVABILITY_VERIFY_EXECUTION_ERROR", `problem-68: sf_verify 行为检查执行失败: ${e.message}`, ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "verifyChangedFilesObservability 必须可运行并返回确定结果", "修复运行时异常");
2537
+ }
2538
+ _info(" problem-68 代码可维护性与可观测性行为验证完成");
2539
+ }
2540
+ // ── 21. 模板卫生与用户项目知识消费验证 ──
2541
+ async function checkTemplateAndProjectKnowledgeHygiene(rootDir, hardFail, _info) {
2542
+ try {
2543
+ const matrix = await import(path.join(rootDir, "dist", "engine", "project_knowledge_system_regression_matrix.js"));
2544
+ const report = matrix.validateProjectKnowledgeSystemMatrix?.();
2545
+ if (!report?.passed) {
2546
+ const messages = (report?.findings ?? []).map((finding) => `${finding.code}: ${finding.message}`).join("; ");
2547
+ hardFail("PROJECT_KNOWLEDGE_SYSTEM_MATRIX_INCOMPLETE", `problem-69: 知识资产与项目规则消费体系 20 项防回归矩阵不完整: ${messages || "未知缺口"}`, ["src/engine/project_knowledge_system_regression_matrix.ts", "docs/SoloForge-Batch8问题集.md"], "problem-69", "旧门禁只检查部分项目知识行为,未覆盖用户讨论的 20 项完整细节", "补齐 20 项矩阵、生产入口、must-fail/must-pass 与文档引用");
2548
+ }
2549
+ }
2550
+ catch (e) {
2551
+ hardFail("PROJECT_KNOWLEDGE_SYSTEM_MATRIX_EXCEPTION", `problem-69: 知识资产与项目规则消费体系矩阵执行失败: ${e.message}`, ["src/engine/project_knowledge_system_regression_matrix.ts"], "problem-69", "项目知识体系矩阵必须可执行", "修复矩阵模块或编译产物");
2552
+ }
2553
+ const scaffoldDir = path.join(rootDir, "templates", "scaffolds");
2554
+ const scaffoldFindings = [];
2555
+ function scanScaffolds(dir) {
2556
+ if (!fs.existsSync(dir))
2557
+ return;
2558
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
2559
+ const full = path.join(dir, entry.name);
2560
+ if (entry.isDirectory()) {
2561
+ scanScaffolds(full);
2562
+ continue;
2563
+ }
2564
+ if (!entry.isFile())
2565
+ continue;
2566
+ const rel = path.relative(rootDir, full).replace(/\\/g, "/");
2567
+ const lines = safeReadLines(full);
2568
+ for (let i = 0; i < lines.length; i++) {
2569
+ if (/\b(?:TODO|FIXME|HACK|XXX)\b/.test(lines[i])) {
2570
+ scaffoldFindings.push(`${rel}:${i + 1}`);
2571
+ }
2572
+ }
2573
+ }
2574
+ }
2575
+ scanScaffolds(scaffoldDir);
2576
+ for (const finding of scaffoldFindings) {
2577
+ hardFail("TEMPLATE_SCAFFOLD_PLACEHOLDER_LEAK", `脚手架模板仍包含未落地占位标记: ${finding}`, [finding.split(":")[0]], "template-hygiene", "历史门禁只检查模板是否注册,不检查用户生成代码是否带 TODO/FIXME", "清理脚手架占位标记并补行为测试");
2578
+ }
2579
+ try {
2580
+ const contractMod = await import(path.join(rootDir, "dist", "engine", "template_asset_contract_registry.js"));
2581
+ const contracts = contractMod.listTemplateAssetContracts?.() ?? [];
2582
+ const forbidden = /\b(?:Batch[1-8]|validate-batch|ReleaseFix|problem-\d+)\b/i;
2583
+ for (const contract of contracts) {
2584
+ if (!contract.user_visible)
2585
+ continue;
2586
+ if (!contract.path || !/\.(md|ya?ml|hbs|json)$/i.test(contract.path))
2587
+ continue;
2588
+ const abs = path.join(rootDir, contract.path);
2589
+ const content = safeRead(abs);
2590
+ if (!content || !forbidden.test(content))
2591
+ continue;
2592
+ hardFail("USER_VISIBLE_TEMPLATE_INTERNAL_TRACE", `用户可见模板泄漏内部施工语义: ${contract.path}`, [contract.path], "template-hygiene", "旧门禁只检查内置资产可见性,不检查用户可见模板内容是否混入内部批次/问题编号", "清理用户可见模板内部语义");
2593
+ }
2594
+ }
2595
+ catch (e) {
2596
+ hardFail("TEMPLATE_CONTRACT_AUDIT_FAILED", `无法执行用户可见模板内容审计: ${e.message}`, ["src/engine/template_asset_contract_registry.ts"], "template-hygiene", "模板内容卫生必须可运行审计", "修复模板合同注册表或编译产物");
2597
+ }
2598
+ try {
2599
+ const obs = await import(path.join(rootDir, "dist", "engine", "code_maintainability_observability_contract.js"));
2600
+ const ordinaryApiImplementationTriggers = obs.requiresCodeObservabilityContract?.("实现机构端入住列表接口", "code_change") === true;
2601
+ if (!ordinaryApiImplementationTriggers) {
2602
+ hardFail("CODE_OBSERVABILITY_BUSINESS_API_NOT_TRIGGERED", "problem-68: 普通业务接口实现未触发代码注释与日志契约,真实项目会绕过问题六十八", ["src/engine/code_maintainability_observability_contract.ts", "src/adapters/claude_code/tools.ts"], "problem-68", "旧行为只覆盖支付/安全等关键词,未覆盖普通 Controller/API/Service 编码", "扩展触发条件并在 sf_expand 聚合返回工作包");
2603
+ }
2604
+ }
2605
+ catch (e) {
2606
+ hardFail("CODE_OBSERVABILITY_TRIGGER_AUDIT_FAILED", `问题六十八触发审计执行失败: ${e.message}`, ["src/engine/code_maintainability_observability_contract.ts"], "problem-68", "触发判断必须可运行", "修复编译或导出");
2607
+ }
2608
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "soloforge-project-knowledge-"));
2609
+ try {
2610
+ const goodDir = path.join(tmp, ".soloforge", "knowledge", "rules");
2611
+ fs.mkdirSync(goodDir, { recursive: true });
2612
+ fs.writeFileSync(path.join(goodDir, "API响应规则.md"), `---
2613
+ id: smartcare-api-response-rule
2614
+ asset_kind: hard_rule
2615
+ routes:
2616
+ - code_change
2617
+ - artifact_generation
2618
+ primary_triggers:
2619
+ - API
2620
+ - 接口
2621
+ - 响应
2622
+ tech_stack:
2623
+ - spring
2624
+ enforcement:
2625
+ level: hard_rule
2626
+ ---
2627
+ # API 响应规则
2628
+
2629
+ 必须使用项目统一响应结构,错误码、字段表和 OpenAPI 保持一致。
2630
+ `, "utf-8");
2631
+ const projectKnowledge = await import(path.join(rootDir, "dist", "engine", "project_knowledge_contract.js"));
2632
+ const report = projectKnowledge.auditProjectKnowledge(tmp);
2633
+ if (report.hard_fail_count !== 0 || report.injectable < 1) {
2634
+ hardFail("PROJECT_KNOWLEDGE_RULE_NOT_CONSUMABLE", "用户项目 .soloforge/knowledge hard rule 未被识别为可消费规则", ["src/engine/project_knowledge_contract.ts"], "project-knowledge-consumption", "旧链路只同步/索引内置模板,未证明用户项目自定义规则可被承载消费", "修复项目知识合同审计与选择逻辑");
2635
+ }
2636
+ const selected = projectKnowledge.selectProjectKnowledgeForTask(report, {
2637
+ intent: "实现机构端 API 接口统一响应",
2638
+ route: "code_change",
2639
+ tech_stack: ["spring"],
2640
+ });
2641
+ if (!selected.some((asset) => asset.id === "smartcare-api-response-rule")) {
2642
+ hardFail("PROJECT_KNOWLEDGE_RULE_NOT_SELECTED", "用户项目自定义 hard rule 未按意图/路由/技术栈被选中", ["src/engine/project_knowledge_contract.ts"], "project-knowledge-consumption", "索引存在不等于任务会消费", "补齐 selectProjectKnowledgeForTask 行为和门禁");
2643
+ }
2644
+ const expander = await import(path.join(rootDir, "dist", "engine", "intent_expander.js"));
2645
+ const expandResult = await expander.expand({
2646
+ intent: "实现机构端 API 接口统一响应",
2647
+ classification: {
2648
+ task_type: "feature",
2649
+ risk: "low",
2650
+ complexity: "low",
2651
+ ambiguity: "low",
2652
+ affected_repos: ["backend"],
2653
+ mode: "autonomous",
2654
+ strategy: "full_pipeline",
2655
+ },
2656
+ projectPath: tmp,
2657
+ config: {
2658
+ name: "release-gate-project-knowledge",
2659
+ tech_stack: {
2660
+ backend: { lang: "java", framework: "spring-boot", version: "3" },
2661
+ frontend: { lang: "typescript", framework: "react", version: "18" },
2662
+ },
2663
+ product_profile: "saas",
2664
+ repos: [{ name: "backend", path: "backend", lang: "java", framework: "spring-boot", scope: ["backend/src/"] }],
2665
+ build_commands: {
2666
+ backend: { build: "mvn compile", test: "mvn test", full: "mvn verify" },
2667
+ frontend: { build: "npm run build", test: "npm test", full: "npm test" },
2668
+ },
2669
+ scope: { backend: ["backend/src/"], frontend: ["src/"] },
2670
+ _projectPath: tmp,
2671
+ },
2672
+ knowledgeIndex: { query: () => [], markUsed: () => { } },
2673
+ route_decision: {
2674
+ route: "code_change",
2675
+ execution_shape: "code_execution",
2676
+ mutation_allowed: true,
2677
+ input_materials: [],
2678
+ missing_required_inputs: [],
2679
+ scope: { read_only: false },
2680
+ constraints: [],
2681
+ language_policy: { primary: "zh" },
2682
+ confidence: 0.9,
2683
+ evidence: [],
2684
+ rejected_routes: [],
2685
+ conflicts: [],
2686
+ decision_version: 1,
2687
+ },
2688
+ });
2689
+ if (!expandResult.project_knowledge?.selected?.some((asset) => asset.id === "smartcare-api-response-rule")
2690
+ || !String(expandResult.prompt).includes("## 用户项目规则")) {
2691
+ hardFail("PROJECT_KNOWLEDGE_NOT_IN_EXPAND_MAINPATH", "用户项目规则未进入 sf_expand 真实 prompt 和结构化结果", ["src/engine/intent_expander.ts", "src/engine/project_knowledge_contract.ts"], "project-knowledge-consumption", "审计/选择通过不等于 MCP 主链路会消费", "将项目规则接入 sf_expand 并补主链路测试");
2692
+ }
2693
+ const nextPlanner = await import(path.join(rootDir, "dist", "engine", "next_action_planner.js"));
2694
+ const nextPlan = await nextPlanner.planNextAction(tmp);
2695
+ if (!nextPlan.project_knowledge_context || nextPlan.project_knowledge_context.total < 1) {
2696
+ hardFail("PROJECT_KNOWLEDGE_NOT_IN_NEXT", "soloforge next 未携带项目知识上下文,用户无法知道下一步会应用哪些项目规则", ["src/engine/next_action_planner.ts", "src/bin/soloforge.ts"], "project-knowledge-consumption", "旧导航只看阶段,不看项目规则", "将项目知识上下文接入 next JSON 和人类输出");
2697
+ }
2698
+ const badTmp = fs.mkdtempSync(path.join(os.tmpdir(), "soloforge-project-knowledge-bad-"));
2699
+ try {
2700
+ const badDir = path.join(badTmp, ".soloforge", "knowledge", "rules");
2701
+ fs.mkdirSync(badDir, { recursive: true });
2702
+ fs.writeFileSync(path.join(badDir, "未路由强规则.md"), "# 未路由强规则\n\n必须使用统一响应。", "utf-8");
2703
+ const badReport = projectKnowledge.auditProjectKnowledge(badTmp);
2704
+ if (badReport.hard_fail_count === 0) {
2705
+ hardFail("PROJECT_KNOWLEDGE_UNROUTED_RULE_FALSE_PASS", "用户项目 hard rule 缺少 routes/primary_triggers 时错误放行", ["src/engine/project_knowledge_contract.ts"], "project-knowledge-consumption", "规则文件存在不等于可稳定消费", "对未路由 hard rule fail-closed");
2706
+ }
2707
+ }
2708
+ finally {
2709
+ fs.rmSync(badTmp, { recursive: true, force: true });
2710
+ }
2711
+ const conflictTmp = fs.mkdtempSync(path.join(os.tmpdir(), "soloforge-project-knowledge-conflict-"));
2712
+ try {
2713
+ const conflictDir = path.join(conflictTmp, ".soloforge", "knowledge", "rules");
2714
+ fs.mkdirSync(conflictDir, { recursive: true });
2715
+ fs.writeFileSync(path.join(conflictDir, "响应A.md"), `---
2716
+ id: response-a
2717
+ asset_kind: hard_rule
2718
+ routes: [code_change]
2719
+ primary_triggers: [API]
2720
+ conflict_group: api_response_format
2721
+ rule_value: ApiResponse
2722
+ enforcement:
2723
+ level: hard_rule
2724
+ ---
2725
+ # 响应 A
2726
+
2727
+ 必须使用 ApiResponse。
2728
+ `, "utf-8");
2729
+ fs.writeFileSync(path.join(conflictDir, "响应B.md"), `---
2730
+ id: response-b
2731
+ asset_kind: hard_rule
2732
+ routes: [code_change]
2733
+ primary_triggers: [API]
2734
+ conflict_group: api_response_format
2735
+ rule_value: Result
2736
+ enforcement:
2737
+ level: hard_rule
2738
+ ---
2739
+ # 响应 B
2740
+
2741
+ 必须使用 Result。
2742
+ `, "utf-8");
2743
+ const conflictReport = projectKnowledge.auditProjectKnowledge(conflictTmp);
2744
+ if (!conflictReport.assets.some((asset) => asset.findings.some((finding) => finding.code === "PROJECT_KNOWLEDGE_RULE_CONFLICT"))) {
2745
+ hardFail("PROJECT_KNOWLEDGE_CONFLICT_FALSE_PASS", "项目 API 响应等规则冲突未进入用户确认", ["src/engine/project_knowledge_contract.ts"], "project-knowledge-consumption", "旧项目知识审计只看是否可选中,不看项目规则之间互斥", "补冲突组/显式 conflicts_with 检测");
2746
+ }
2747
+ }
2748
+ finally {
2749
+ fs.rmSync(conflictTmp, { recursive: true, force: true });
2750
+ }
2751
+ }
2752
+ catch (e) {
2753
+ hardFail("PROJECT_KNOWLEDGE_AUDIT_FAILED", `用户项目知识消费行为审计执行失败: ${e.message}`, ["src/engine/project_knowledge_contract.ts"], "project-knowledge-consumption", "项目知识消费必须有可执行行为门禁", "修复项目知识合同模块和编译产物");
2754
+ }
2755
+ finally {
2756
+ fs.rmSync(tmp, { recursive: true, force: true });
2757
+ }
2758
+ _info(" 模板卫生与项目知识消费验证完成");
2759
+ }
2760
+ async function checkLongTermMechanization(rootDir, hardFail, _info) {
2761
+ try {
2762
+ const matrix = await import("./historical_issue_mechanization_matrix.js");
2763
+ const report = matrix.validateHistoricalIssueMechanizationMatrix?.();
2764
+ if (!report?.passed) {
2765
+ const messages = (report?.findings ?? []).map((finding) => `${finding.code}: ${finding.message}`).join("; ");
2766
+ hardFail("HISTORICAL_FIRST_PRINCIPLES_MATRIX_INCOMPLETE", `历史问题第一性原理机制化矩阵不完整: ${messages || "未知缺口"}`, ["src/engine/historical_issue_mechanization_matrix.ts", "docs/SoloForge-Batch8问题集.md"], "problem-70", "旧复审只统计 mechanized/partial/not,不强制每个历史问题归入长期机制族", "补齐历史问题机制族、生产入口、must-fail/must-pass 和发布门禁");
2767
+ }
2768
+ }
2769
+ catch (e) {
2770
+ hardFail("HISTORICAL_FIRST_PRINCIPLES_MATRIX_EXCEPTION", `历史问题第一性原理矩阵检查异常: ${e.message}`, ["src/engine/historical_issue_mechanization_matrix.ts"], "problem-70", "旧 gate 不执行历史问题矩阵", "修复历史问题机制化矩阵模块");
2771
+ }
2772
+ try {
2773
+ const health = await import("./mechanism_health_check.js");
2774
+ const report = health.runFullHealthCheck(rootDir);
2775
+ for (const finding of report.findings.filter((f) => f.severity === "hard_fail")) {
2776
+ hardFail("LONGTERM_MECHANISM_HEALTH", finding.message_zh, [finding.target], "历史问题长期机制化", "旧 gate 不检查机制死代码/未消费资产", "修复机制消费链路");
2777
+ }
2778
+ }
2779
+ catch (e) {
2780
+ hardFail("LONGTERM_MECHANISM_HEALTH_EXCEPTION", `机制运行时健康度检查异常: ${e.message}`, ["src/engine/mechanism_health_check.ts"], "历史问题长期机制化", "旧 gate 不执行机制健康检查", "修复检查模块");
2781
+ }
2782
+ try {
2783
+ const kg = await import("./knowledge_governance_gate.js");
2784
+ const report = kg.runKnowledgeGovernanceCheck({
2785
+ project_language: "zh",
2786
+ contents: [{ id: "release-gate", domain: "user_feedback", content: "发布门禁保持中文语义优先" }],
2787
+ });
2788
+ if (report.hard_fail_count > 0) {
2789
+ hardFail("LONGTERM_KNOWLEDGE_GOVERNANCE", `知识治理存在 ${report.hard_fail_count} 个 hard_fail`, ["src/engine/knowledge_governance_gate.ts"], "历史问题长期机制化", "旧 gate 只跑历史知识场景,不接统一治理入口", "修复知识治理检查");
2790
+ }
2791
+ }
2792
+ catch (e) {
2793
+ hardFail("LONGTERM_KNOWLEDGE_GOVERNANCE_EXCEPTION", `知识治理检查异常: ${e.message}`, ["src/engine/knowledge_governance_gate.ts"], "历史问题长期机制化", "旧 gate 不执行知识治理入口", "修复检查模块");
2794
+ }
2795
+ try {
2796
+ const logGov = await import("./log_governance.js");
2797
+ const clean = logGov.enforceLogGovernance("用户可见输出保持中文且无内部噪音");
2798
+ const noisy = logGov.enforceLogGovernance("[soloForge] internal trace validate-release");
2799
+ if (!clean.passed || noisy.passed) {
2800
+ hardFail("LONGTERM_LOG_GOVERNANCE_BEHAVIOR", "日志治理 must-pass/must-fail 行为不成立", ["src/engine/log_governance.ts"], "历史问题长期机制化", "旧 gate 只扫描 console,不验证输出治理行为", "修复 log_governance 行为");
2801
+ }
2802
+ }
2803
+ catch (e) {
2804
+ hardFail("LONGTERM_LOG_GOVERNANCE_EXCEPTION", `日志治理检查异常: ${e.message}`, ["src/engine/log_governance.ts"], "历史问题长期机制化", "旧 gate 不执行日志治理入口", "修复检查模块");
2805
+ }
2806
+ try {
2807
+ const cfg = await import("./config_write_boundary.js");
2808
+ const runtimeCtx = cfg.classifyConfigContext(rootDir, { runtime_inference: true });
2809
+ const runtimeDecision = cfg.isWriteAllowed(runtimeCtx, path.join(rootDir, ".soloforge", "config.yaml"));
2810
+ const greenfieldDecision = cfg.isWriteAllowed({ kind: "greenfield", project_path: rootDir, evidence: ["empty_project"], confirmed: false }, path.join(rootDir, ".soloforge", "config.yaml"));
2811
+ if (runtimeDecision.allowed || !greenfieldDecision.allowed) {
2812
+ hardFail("LONGTERM_CONFIG_BOUNDARY_BEHAVIOR", "配置落盘边界 must-pass/must-fail 行为不成立", ["src/engine/config_write_boundary.ts"], "历史问题长期机制化", "旧 gate 不区分运行时推断与空项目写入", "修复配置写入边界");
2813
+ }
2814
+ }
2815
+ catch (e) {
2816
+ hardFail("LONGTERM_CONFIG_BOUNDARY_EXCEPTION", `配置落盘边界检查异常: ${e.message}`, ["src/engine/config_write_boundary.ts"], "历史问题长期机制化", "旧 gate 不执行配置落盘边界", "修复检查模块");
2817
+ }
2818
+ _info(" 历史问题长期机制化行为验证完成");
2819
+ }
2820
+ async function checkDiagnosticCentralization(rootDir, hardFail) {
2821
+ const toolsPath = path.join(rootDir, "src", "adapters", "claude_code", "tools.ts");
2822
+ const toolsText = safeRead(toolsPath) ?? "";
2823
+ const literalMatches = [...toolsText.matchAll(/["'`]SF-[A-Z]+-\d{4}["'`]/g)];
2824
+ if (literalMatches.length > 0) {
2825
+ hardFail("DIAGNOSTIC_CODE_HARDCODED_IN_TOOLS", `tools.ts 仍有 ${literalMatches.length} 个硬编码诊断码字面量`, ["src/adapters/claude_code/tools.ts"], "problem-36", "旧 gate 不检查诊断码集中治理", "改用 diagnostic_registry 导出的 TOOL_DIAGNOSTIC_CODES");
2826
+ }
2827
+ const registry = await import("./diagnostic_registry.js");
2828
+ const required = Object.values(registry.TOOL_DIAGNOSTIC_CODES);
2829
+ const registered = new Set(registry.listAllDiagnostics().map((d) => d.code));
2830
+ const missing = required.filter((code) => !registered.has(code));
2831
+ if (missing.length > 0) {
2832
+ hardFail("DIAGNOSTIC_CODE_REGISTRY_MISSING", `诊断码常量未在注册表登记: ${missing.join(", ")}`, ["src/engine/diagnostic_registry.ts"], "problem-36", "旧 gate 不检查诊断码注册完整性", "补齐 BUILTIN_DIAGNOSTICS");
2833
+ }
2834
+ }
2220
2835
  // ── 主入口 ──
2221
2836
  export async function runReleaseReadinessGate(rootDir) {
2222
2837
  const hardFails = [];
@@ -2315,6 +2930,22 @@ export async function runReleaseReadinessGate(rootDir) {
2315
2930
  beginPhase("实现工程契约行为验证");
2316
2931
  await checkImplementationContractBehavior(rootDir, hardFail, _info);
2317
2932
  endPhase("实现工程契约行为验证");
2933
+ // 18: 代码可维护性与可观测性契约行为验证(问题六十八)
2934
+ beginPhase("代码可维护性与可观测性行为验证");
2935
+ await checkCodeObservabilityBehavior(rootDir, hardFail, _info);
2936
+ endPhase("代码可维护性与可观测性行为验证");
2937
+ // 19: 历史问题长期机制化行为验证
2938
+ beginPhase("历史问题长期机制化行为验证");
2939
+ await checkLongTermMechanization(rootDir, hardFail, _info);
2940
+ endPhase("历史问题长期机制化行为验证");
2941
+ // 20: 诊断码集中治理检查
2942
+ beginPhase("诊断码集中治理检查");
2943
+ await checkDiagnosticCentralization(rootDir, hardFail);
2944
+ endPhase("诊断码集中治理检查");
2945
+ // 21: 模板卫生与用户项目知识消费验证
2946
+ beginPhase("模板卫生与项目知识消费验证");
2947
+ await checkTemplateAndProjectKnowledgeHygiene(rootDir, hardFail, _info);
2948
+ endPhase("模板卫生与项目知识消费验证");
2318
2949
  // 恢复 console.error 和日志器
2319
2950
  console.error = origConsoleError;
2320
2951
  resetLogger();