soloforge 1.3.0 → 1.3.1

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 (84) hide show
  1. package/README.md +10 -0
  2. package/dist/adapters/claude_code/tools.d.ts +27 -0
  3. package/dist/adapters/claude_code/tools.d.ts.map +1 -1
  4. package/dist/adapters/claude_code/tools.js +513 -3
  5. package/dist/adapters/claude_code/tools.js.map +1 -1
  6. package/dist/adapters/shared/workflow_template.d.ts.map +1 -1
  7. package/dist/adapters/shared/workflow_template.js +6 -0
  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 +147 -4
  11. package/dist/bin/soloforge.js.map +1 -1
  12. package/dist/engine/architecture_decision_workshop.d.ts +58 -0
  13. package/dist/engine/architecture_decision_workshop.d.ts.map +1 -0
  14. package/dist/engine/architecture_decision_workshop.js +118 -0
  15. package/dist/engine/architecture_decision_workshop.js.map +1 -0
  16. package/dist/engine/asset_manifest.d.ts.map +1 -1
  17. package/dist/engine/asset_manifest.js +11 -0
  18. package/dist/engine/asset_manifest.js.map +1 -1
  19. package/dist/engine/consumable_asset_registry.d.ts.map +1 -1
  20. package/dist/engine/consumable_asset_registry.js +64 -1
  21. package/dist/engine/consumable_asset_registry.js.map +1 -1
  22. package/dist/engine/design_artifact_pack.d.ts +44 -0
  23. package/dist/engine/design_artifact_pack.d.ts.map +1 -0
  24. package/dist/engine/design_artifact_pack.js +167 -0
  25. package/dist/engine/design_artifact_pack.js.map +1 -0
  26. package/dist/engine/dual_layer_mechanism_registry.d.ts.map +1 -1
  27. package/dist/engine/dual_layer_mechanism_registry.js +120 -0
  28. package/dist/engine/dual_layer_mechanism_registry.js.map +1 -1
  29. package/dist/engine/evidence_grounding_contract.d.ts +137 -0
  30. package/dist/engine/evidence_grounding_contract.d.ts.map +1 -0
  31. package/dist/engine/evidence_grounding_contract.js +410 -0
  32. package/dist/engine/evidence_grounding_contract.js.map +1 -0
  33. package/dist/engine/implementation_roadmap_registry.d.ts +1 -1
  34. package/dist/engine/implementation_roadmap_registry.d.ts.map +1 -1
  35. package/dist/engine/implementation_roadmap_registry.js +134 -5
  36. package/dist/engine/implementation_roadmap_registry.js.map +1 -1
  37. package/dist/engine/instruction_contract.d.ts +8 -1
  38. package/dist/engine/instruction_contract.d.ts.map +1 -1
  39. package/dist/engine/instruction_contract.js +63 -1
  40. package/dist/engine/instruction_contract.js.map +1 -1
  41. package/dist/engine/intent_expander.d.ts.map +1 -1
  42. package/dist/engine/intent_expander.js +14 -0
  43. package/dist/engine/intent_expander.js.map +1 -1
  44. package/dist/engine/mechanism_contract_registry.d.ts.map +1 -1
  45. package/dist/engine/mechanism_contract_registry.js +66 -0
  46. package/dist/engine/mechanism_contract_registry.js.map +1 -1
  47. package/dist/engine/platform_context.d.ts.map +1 -1
  48. package/dist/engine/platform_context.js +6 -2
  49. package/dist/engine/platform_context.js.map +1 -1
  50. package/dist/engine/release_gate_scenario_registry.d.ts +16 -1
  51. package/dist/engine/release_gate_scenario_registry.d.ts.map +1 -1
  52. package/dist/engine/release_gate_scenario_registry.js +205 -2
  53. package/dist/engine/release_gate_scenario_registry.js.map +1 -1
  54. package/dist/engine/release_readiness_gate.d.ts +8 -0
  55. package/dist/engine/release_readiness_gate.d.ts.map +1 -1
  56. package/dist/engine/release_readiness_gate.js +616 -6
  57. package/dist/engine/release_readiness_gate.js.map +1 -1
  58. package/dist/engine/task_context.d.ts +9 -2
  59. package/dist/engine/task_context.d.ts.map +1 -1
  60. package/dist/engine/task_context.js +49 -12
  61. package/dist/engine/task_context.js.map +1 -1
  62. package/dist/engine/verifier.d.ts.map +1 -1
  63. package/dist/engine/verifier.js +3 -40
  64. package/dist/engine/verifier.js.map +1 -1
  65. package/dist/engine/workflow_contract_registry.d.ts.map +1 -1
  66. package/dist/engine/workflow_contract_registry.js +4 -3
  67. package/dist/engine/workflow_contract_registry.js.map +1 -1
  68. package/dist/types.d.ts +12 -0
  69. package/dist/types.d.ts.map +1 -1
  70. package/package.json +4 -3
  71. package/templates/knowledge/acceptance_templates/API/346/216/245/345/217/243/350/247/204/346/240/274/346/226/207/346/241/243/346/250/241/347/211/210.md +74 -0
  72. package/templates/knowledge/acceptance_templates//346/225/260/346/215/256/345/272/223/350/256/276/350/256/241/346/226/207/346/241/243/346/250/241/347/211/210.md +59 -0
  73. package/templates/knowledge/acceptance_templates//346/236/266/346/236/204/350/256/276/350/256/241/346/250/241/347/211/210.md +27 -7
  74. package/templates/knowledge/acceptance_templates//350/256/276/350/256/241/344/270/200/350/207/264/346/200/247/351/252/214/346/224/266/346/212/245/345/221/212/346/250/241/347/211/210.md +47 -0
  75. package/templates/knowledge/procedures//346/236/266/346/236/204/345/206/263/347/255/226/347/240/224/350/256/250/345/267/245/344/275/234/346/265/201.md +51 -0
  76. package/templates/knowledge/procedures//346/236/266/346/236/204/350/256/276/350/256/241/345/267/245/344/275/234/346/265/201.md +16 -7
  77. package/templates/knowledge/procedures//350/256/276/350/256/241/344/272/247/347/211/251/347/224/237/346/210/220/344/270/216/345/244/215/351/252/214/345/267/245/344/275/234/346/265/201.md +45 -0
  78. package/templates/knowledge/rules//345/267/245/344/275/234/346/265/201/346/250/241/346/235/277/345/214/205/350/247/204/345/210/231.md +10 -0
  79. package/templates/knowledge/rules//346/211/251/345/261/225/347/224/237/345/221/275/345/221/250/346/234/237/350/247/204/345/210/231.md +10 -0
  80. package/templates/knowledge/rules//346/226/275/345/267/245/346/214/207/344/273/244/345/245/221/347/272/246/350/247/204/345/210/231.md +33 -4
  81. package/templates/knowledge/rules//346/236/266/346/236/204/345/206/263/347/255/226/347/240/224/350/256/250/350/247/204/345/210/231.md +49 -0
  82. package/templates/knowledge/rules//350/256/276/350/256/241/344/272/247/347/211/251/345/214/205/350/247/204/345/210/231.md +55 -0
  83. package/templates/knowledge/rules//350/257/201/346/215/256/351/251/261/345/212/250/344/270/216/345/217/215/345/271/273/350/247/211/350/247/204/345/210/231.md +75 -0
  84. package/templates/knowledge/rules//350/267/250/345/271/263/345/217/260/350/267/257/345/276/204/345/256/211/345/205/250/350/247/204/345/210/231.md +10 -0
@@ -13,6 +13,14 @@
13
13
  * 5. 旧 gate 误导标记
14
14
  * 6. 测试污染初筛
15
15
  * 7. Batch 问题文档格式一致性
16
+ * 8. 关键问题消费验证
17
+ * 9. 机制身份一致性
18
+ * 10. P0/P1 知识资产 schema
19
+ * 11. engine console.log 检查
20
+ * 12. 中文注释检查
21
+ * 13. 第五批一致性校验
22
+ * 14. 依赖漏洞扫描
23
+ * 15. Batch6 架构决策与设计产物真实消费
16
24
  */
17
25
  import fs from "node:fs";
18
26
  import path from "node:path";
@@ -218,7 +226,7 @@ const CONSUMER_ENTRY_FILES = {
218
226
  "CLI validate-knowledge": ["src/engine/knowledge_scenario_registry.ts"],
219
227
  "sf_verify": ["src/engine/verifier.ts"],
220
228
  "sf_deliver": ["src/adapters/claude_code/tools.ts", "src/engine/delivery_readiness.ts"],
221
- "sf_expand": ["src/engine/intent_expander.ts"],
229
+ "sf_expand": ["src/adapters/claude_code/tools.ts", "src/engine/intent_expander.ts"],
222
230
  "问题管理流程": [],
223
231
  };
224
232
  /** 模块名→文件路径映射 (用于模块间调用链如 "knowledge_evolution.validateCandidateTrust") */
@@ -435,7 +443,15 @@ function checkMainlineConsumption(rootDir, hardFail, _info) {
435
443
  continue;
436
444
  const staticImportPattern = new RegExp(`import\\s+\\{[^}]*\\b${ep}\\b[^}]*\\}\\s+from`);
437
445
  const dynamicImportPattern = new RegExp(`\\{[^}]*\\b${ep}\\b[^}]*\\}\\s*=\\s*await\\s+import\\(`);
438
- const hasImport = staticImportPattern.test(consumerContent) || dynamicImportPattern.test(consumerContent);
446
+ const hasLazyModuleImport = entry.owner_files.some((ownerFile) => {
447
+ const moduleName = path.basename(ownerFile, ".ts");
448
+ return consumerContent.includes(`import("../../engine/${moduleName}.js")`)
449
+ || consumerContent.includes(`import("../engine/${moduleName}.js")`)
450
+ || consumerContent.includes(`import("./${moduleName}.js")`);
451
+ });
452
+ const hasImport = staticImportPattern.test(consumerContent)
453
+ || dynamicImportPattern.test(consumerContent)
454
+ || hasLazyModuleImport;
439
455
  if (!hasImport)
440
456
  continue;
441
457
  const importLinePattern = new RegExp(`import\\s+\\{[^}]*\\b${ep}\\b|\\{[^}]*\\b${ep}\\b[^}]*\\}\\s*=\\s*await\\s+import`);
@@ -636,7 +652,7 @@ function checkTestPollution(rootDir, hardFail, _info) {
636
652
  }
637
653
  }
638
654
  // ── 8. 关键问题消费验证 (problem-17/38/57) ──
639
- function checkCriticalProblemConsumption(rootDir, hardFail, _info) {
655
+ async function checkCriticalProblemConsumption(rootDir, hardFail, _info) {
640
656
  const taskContextPath = path.join(rootDir, "src/engine/task_context.ts");
641
657
  const cliPath = path.join(rootDir, "src/bin/soloforge.ts");
642
658
  // problem-17: StateFact 分区 — save() 必须调用 validateStateFactPartition,hard_fail 必须 throw
@@ -765,6 +781,342 @@ function checkCriticalProblemConsumption(rootDir, hardFail, _info) {
765
781
  }
766
782
  }
767
783
  _info(" problem-17/38/57 消费验证完成");
784
+ // 问题六十:证据驱动与反幻觉契约 — 行为级检查
785
+ {
786
+ const evidenceGroundingPath = path.join(rootDir, "src/engine/evidence_grounding_contract.ts");
787
+ if (!fs.existsSync(evidenceGroundingPath)) {
788
+ hardFail("CRITICAL_PROBLEM_FILE_MISSING", "problem-60: evidence_grounding_contract.ts 不存在", ["src/engine/evidence_grounding_contract.ts"], "problem-60", "发布门禁不检查 problem-60 实现", "创建 evidence_grounding_contract.ts");
789
+ }
790
+ else {
791
+ // 行为级检查:动态导入并验证核心门禁行为
792
+ try {
793
+ const eg = await import(path.join(rootDir, "dist/engine/evidence_grounding_contract.js"));
794
+ const sys = eg.createEvidenceGroundingSystem();
795
+ // 检查 1:无证据高风险 claim 必须被 blocked
796
+ {
797
+ const noEvClaims = [{
798
+ id: "gate-test-no-ev", claim_text: "项目使用 React", category: "project_fact",
799
+ evidence_ids: [], is_uncertain: false, risk_level: "high",
800
+ }];
801
+ const noEvResult = sys.verifier.verify(noEvClaims, "high");
802
+ if (noEvResult.unsupported.length === 0) {
803
+ hardFail("CRITICAL_PROBLEM_BEHAVIOR", "problem-60: 无证据高风险 claim 未被 blocked", ["src/engine/evidence_grounding_contract.ts"], "problem-60", "FactClaimVerifier 未阻断无证据声明", "验证 classify 逻辑");
804
+ }
805
+ }
806
+ // 检查 2:generated_inference 单独支撑 project_fact 必须被 blocked
807
+ {
808
+ const infEv = sys.registry.register({
809
+ source_type: "generated_inference", authority: "weak", freshness: "unknown",
810
+ permission: "allowed", scope: "test", description: "推理",
811
+ });
812
+ const infClaims = [{
813
+ id: "gate-test-inference", claim_text: "项目使用 Vue", category: "tech_stack",
814
+ evidence_ids: [infEv.id], is_uncertain: false, risk_level: "high",
815
+ }];
816
+ const infResult = sys.verifier.verify(infClaims, "high");
817
+ if (infResult.unsupported.length === 0) {
818
+ hardFail("CRITICAL_PROBLEM_BEHAVIOR", "problem-60: generated_inference 单独支撑 project_fact 未被 blocked", ["src/engine/evidence_grounding_contract.ts"], "problem-60", "FactClaimVerifier 未阻断推理自证", "验证 isSelfAttestation 逻辑");
819
+ }
820
+ }
821
+ // 检查 3:validation_plan 冒充 validation_result 必须被 blocked
822
+ {
823
+ const planEv = sys.registry.register({
824
+ source_type: "generated_inference", authority: "weak", freshness: "unknown",
825
+ permission: "allowed", scope: "test", description: "验证计划",
826
+ });
827
+ const planClaims = [{
828
+ id: "gate-test-plan-as-result", claim_text: "验证已通过",
829
+ category: "validation_result",
830
+ evidence_ids: [planEv.id], is_uncertain: false, risk_level: "high",
831
+ }];
832
+ const planResult = sys.verifier.verify(planClaims, "high");
833
+ if (planResult.unsupported.length === 0) {
834
+ hardFail("CRITICAL_PROBLEM_BEHAVIOR", "problem-60: validation_plan 冒充 validation_result 未被 blocked", ["src/engine/evidence_grounding_contract.ts"], "problem-60", "FactClaimVerifier 未阻断验证计划冒充", "验证 validation_result 检查逻辑");
835
+ }
836
+ }
837
+ // 检查 4:forbidden source 必须被 blocked
838
+ {
839
+ const matrix = sys.builder.buildContext([], {
840
+ target_claims: [], source_types: [], keywords: [], max_results: 10,
841
+ });
842
+ matrix.evidence.push({
843
+ id: "ev-forbidden-test", source_type: "project_file",
844
+ authority: "authoritative", freshness: "current",
845
+ permission: "forbidden", scope: "sensitive",
846
+ description: "敏感数据", timestamp: new Date().toISOString(),
847
+ });
848
+ matrix.risk_summary = { low: 0, medium: 0, high: 0, critical: 1 };
849
+ const forbiddenResult = sys.gate.evaluate(matrix, "high");
850
+ if (forbiddenResult.allowed) {
851
+ hardFail("CRITICAL_PROBLEM_BEHAVIOR", "problem-60: forbidden source 未被 UnsupportedClaimGate 阻断", ["src/engine/evidence_grounding_contract.ts"], "problem-60", "UnsupportedClaimGate 允许 forbidden 证据通过", "验证 forbidden 检查逻辑");
852
+ }
853
+ }
854
+ // 检查 5:conflict unresolved 必须被 blocked(高风险)
855
+ {
856
+ const confMatrix = sys.builder.buildContext([], {
857
+ target_claims: [], source_types: [], keywords: [], max_results: 10,
858
+ });
859
+ confMatrix.conflicts.push({
860
+ claim_id: "claim-conflict-test",
861
+ conflicting_evidence_ids: ["ev-a", "ev-b"],
862
+ description: "矛盾",
863
+ resolution_status: "unresolved",
864
+ });
865
+ confMatrix.risk_summary = { low: 0, medium: 0, high: 1, critical: 0 };
866
+ const confResult = sys.gate.evaluate(confMatrix, "high");
867
+ if (confResult.allowed) {
868
+ hardFail("CRITICAL_PROBLEM_BEHAVIOR", "problem-60: unresolved conflict 未被 UnsupportedClaimGate 阻断", ["src/engine/evidence_grounding_contract.ts"], "problem-60", "UnsupportedClaimGate 允许未裁决冲突通过", "验证 conflict 检查逻辑");
869
+ }
870
+ }
871
+ // 检查 6:classification-only 证据不得支撑 architecture 声明
872
+ {
873
+ sys.registry.clear();
874
+ const clsOnlyEv = sys.registry.register({
875
+ source_type: "task_context", authority: "authoritative", freshness: "current",
876
+ permission: "allowed", scope: "classification", description: "任务分类结果",
877
+ });
878
+ const clsOnlyClaims = [{
879
+ id: "gate-test-cls-only", claim_text: "技术方案基于现有系统分析",
880
+ category: "architecture",
881
+ evidence_ids: [clsOnlyEv.id], is_uncertain: false, risk_level: "high",
882
+ }];
883
+ const clsOnlyResult = sys.verifier.verify(clsOnlyClaims, "high");
884
+ if (clsOnlyResult.unsupported.length === 0) {
885
+ hardFail("CRITICAL_PROBLEM_BEHAVIOR", "problem-60: classification-only 证据支撑 architecture 声明未被 blocked", ["src/engine/evidence_grounding_contract.ts"], "problem-60", "FactClaimVerifier 允许 task_context:classification 支撑项目事实声明", "验证 CATEGORY_REQUIRED_SOURCES 逻辑");
886
+ }
887
+ }
888
+ // 检查 7:project_file + project_source_file 证据可以支撑 architecture 声明
889
+ {
890
+ sys.registry.clear();
891
+ const pfEv = sys.registry.register({
892
+ source_type: "project_file", evidence_role: "project_source_file",
893
+ authority: "authoritative", freshness: "current",
894
+ permission: "allowed", scope: "src/", description: "项目源码文件",
895
+ });
896
+ const pfClaims = [{
897
+ id: "gate-test-pf-ok", claim_text: "技术方案基于现有系统分析",
898
+ category: "architecture",
899
+ evidence_ids: [pfEv.id], is_uncertain: false, risk_level: "high",
900
+ }];
901
+ const pfResult = sys.verifier.verify(pfClaims, "high");
902
+ if (pfResult.unsupported.length > 0) {
903
+ hardFail("CRITICAL_PROBLEM_BEHAVIOR", "problem-60: project_source_file 证据支撑 architecture 声明被错误 blocked", ["src/engine/evidence_grounding_contract.ts"], "problem-60", "FactClaimVerifier 误阻断了有效证据", "验证 CATEGORY_REQUIRED_ROLES 逻辑");
904
+ }
905
+ }
906
+ // 检查 8:template_guidance 证据不得支撑 architecture 声明
907
+ {
908
+ sys.registry.clear();
909
+ const tgEv = sys.registry.register({
910
+ source_type: "knowledge_asset", evidence_role: "template_guidance",
911
+ authority: "trusted", freshness: "current",
912
+ permission: "allowed", scope: "knowledge", description: "默认模板",
913
+ });
914
+ const tgClaims = [{
915
+ id: "gate-test-tg-block", claim_text: "技术方案基于现有系统分析",
916
+ category: "architecture",
917
+ evidence_ids: [tgEv.id], is_uncertain: false, risk_level: "high",
918
+ }];
919
+ const tgResult = sys.verifier.verify(tgClaims, "high");
920
+ if (tgResult.unsupported.length === 0) {
921
+ hardFail("CRITICAL_PROBLEM_BEHAVIOR", "problem-60: template_guidance 证据支撑 architecture 声明未被 blocked", ["src/engine/evidence_grounding_contract.ts"], "problem-60", "FactClaimVerifier 允许 template_guidance 支撑项目事实声明", "验证 CATEGORY_REQUIRED_ROLES 逻辑");
922
+ }
923
+ }
924
+ // 检查 9:project_source_file 证据角色可以支撑 architecture 声明
925
+ {
926
+ sys.registry.clear();
927
+ const psfEv = sys.registry.register({
928
+ source_type: "project_file", evidence_role: "project_source_file",
929
+ authority: "authoritative", freshness: "current",
930
+ permission: "allowed", scope: "src/", description: "项目源码文件",
931
+ });
932
+ const psfClaims = [{
933
+ id: "gate-test-psf-ok", claim_text: "技术方案基于现有系统分析",
934
+ category: "architecture",
935
+ evidence_ids: [psfEv.id], is_uncertain: false, risk_level: "high",
936
+ }];
937
+ const psfResult = sys.verifier.verify(psfClaims, "high");
938
+ if (psfResult.unsupported.length > 0) {
939
+ hardFail("CRITICAL_PROBLEM_BEHAVIOR", "problem-60: project_source_file 角色支撑 architecture 声明被错误 blocked", ["src/engine/evidence_grounding_contract.ts"], "problem-60", "FactClaimVerifier 误阻断了有效 project_source_file 证据", "验证 CATEGORY_REQUIRED_ROLES 逻辑");
940
+ }
941
+ }
942
+ // 检查 10:普通 code_change 不应因无 project_source_file 被 blocked(无 architecture claim 时)
943
+ {
944
+ sys.registry.clear();
945
+ const clsEv = sys.registry.register({
946
+ source_type: "task_context", evidence_role: "classification",
947
+ authority: "authoritative", freshness: "current",
948
+ permission: "allowed", scope: "classification", description: "任务分类结果",
949
+ });
950
+ // 普通 code_change 只有 user_confirmation claim(无 architecture claim)
951
+ const ccClaims = [{
952
+ id: "gate-test-cc-ok", claim_text: "任务路由和执行范围已确认",
953
+ category: "user_confirmation",
954
+ evidence_ids: [clsEv.id], is_uncertain: false, risk_level: "high",
955
+ }];
956
+ const ccResult = sys.verifier.verify(ccClaims, "high");
957
+ if (ccResult.unsupported.length > 0) {
958
+ hardFail("CRITICAL_PROBLEM_BEHAVIOR", "problem-60: 普通 code_change 的 user_confirmation claim 被 classification 证据错误 blocked", ["src/engine/evidence_grounding_contract.ts"], "problem-60", "FactClaimVerifier 误阻断了不需要项目事实的普通任务", "验证 claim 语义逻辑");
959
+ }
960
+ }
961
+ // 检查 11:architecture_design 无真实项目证据必须 blocked
962
+ {
963
+ sys.registry.clear();
964
+ const clsOnlyEv = sys.registry.register({
965
+ source_type: "task_context", evidence_role: "classification",
966
+ authority: "authoritative", freshness: "current",
967
+ permission: "allowed", scope: "classification", description: "任务分类结果",
968
+ });
969
+ const tgOnlyEv = sys.registry.register({
970
+ source_type: "knowledge_asset", evidence_role: "template_guidance",
971
+ authority: "trusted", freshness: "current",
972
+ permission: "allowed", scope: "knowledge", description: "默认模板",
973
+ });
974
+ const archClaims = [{
975
+ id: "gate-test-arch-block", claim_text: "技术方案基于现有系统分析",
976
+ category: "architecture",
977
+ evidence_ids: [clsOnlyEv.id, tgOnlyEv.id], is_uncertain: false, risk_level: "high",
978
+ }];
979
+ const archResult = sys.verifier.verify(archClaims, "high");
980
+ if (archResult.unsupported.length === 0) {
981
+ hardFail("CRITICAL_PROBLEM_BEHAVIOR", "problem-60: architecture_design 无真实项目证据未被 blocked(classification + template_guidance 不够)", ["src/engine/evidence_grounding_contract.ts"], "problem-60", "FactClaimVerifier 允许非项目证据支撑架构声明", "验证 CATEGORY_REQUIRED_ROLES + claim 语义逻辑");
982
+ }
983
+ }
984
+ }
985
+ catch (behaviorErr) {
986
+ hardFail("CRITICAL_PROBLEM_BEHAVIOR", `problem-60: 行为级检查执行失败: ${behaviorErr?.message ?? behaviorErr}`, ["src/engine/evidence_grounding_contract.ts"], "problem-60", "证据驱动机制行为检查不可执行", "修复 import 或机制代码");
987
+ }
988
+ }
989
+ // 静态检查:导出完整性
990
+ const egContent = safeRead(evidenceGroundingPath);
991
+ if (egContent) {
992
+ const requiredExports = ["createEvidenceGroundingSystem", "assessTaskRisk", "EvidenceSourceRegistry", "FactClaimVerifier", "UnsupportedClaimGate"];
993
+ for (const exp of requiredExports) {
994
+ if (!egContent.includes(exp)) {
995
+ hardFail("CRITICAL_PROBLEM_EXPORT_MISSING", `problem-60: evidence_grounding_contract.ts 缺少导出: ${exp}`, ["src/engine/evidence_grounding_contract.ts"], "problem-60", "证据驱动机制缺少核心导出", `添加 ${exp} 导出`);
996
+ }
997
+ }
998
+ }
999
+ // 静态检查:InstructionContract schema 必须包含 evidence 字段
1000
+ const instrContractPath = path.join(rootDir, "src/engine/instruction_contract.ts");
1001
+ const instrContent = safeRead(instrContractPath);
1002
+ if (instrContent) {
1003
+ const evidenceFields = ["evidence_matrix", "unsupported_claim_policy", "uncertainty_policy", "conflict_resolution_policy"];
1004
+ for (const field of evidenceFields) {
1005
+ if (!instrContent.includes(field)) {
1006
+ hardFail("CRITICAL_PROBLEM_SCHEMA_INCOMPLETE", `problem-60: instruction_contract.ts schema 缺少证据字段: ${field}`, ["src/engine/instruction_contract.ts"], "problem-60", "施工指令契约缺少证据驱动字段", `添加 ${field} 字段`);
1007
+ }
1008
+ }
1009
+ }
1010
+ // 静态检查:主链路必须有 runtime 阻断(不能只是 advisory)
1011
+ const toolsPath = path.join(rootDir, "src/adapters/claude_code/tools.ts");
1012
+ const toolsContent = safeRead(toolsPath);
1013
+ if (!toolsContent?.includes("evidence_grounding_contract")) {
1014
+ hardFail("CRITICAL_PROBLEM_NOT_CONSUMED", "problem-60: tools.ts 未消费 evidence_grounding_contract", ["src/adapters/claude_code/tools.ts"], "problem-60", "证据驱动机制未接入主链路", "在 sf_expand/sf_verify/sf_deliver 中接入");
1015
+ }
1016
+ // sf_expand 必须有 blocked/manual_required 分支
1017
+ if (toolsContent && !toolsContent.includes("_evGate.allowed") && !toolsContent.includes("evidence_blocked")) {
1018
+ hardFail("CRITICAL_PROBLEM_ADVISORY_ONLY", "problem-60: sf_expand 证据检查只有 advisory,缺少 blocked 分支", ["src/adapters/claude_code/tools.ts"], "problem-60", "sf_expand 证据门禁不阻断", "添加 evidence gate blocked 分支");
1019
+ }
1020
+ // sf_verify: 验证计划描述行中不得包含 source_type: "validation_result"
1021
+ if (toolsContent) {
1022
+ // 找到 sf_verify handler 中问题六十部分
1023
+ const verifyStart = toolsContent.indexOf("问题六十:验证结论必须经过 FactClaimVerifier");
1024
+ const verifyEnd = toolsContent.indexOf("// 验证后核心体验评估", verifyStart);
1025
+ if (verifyStart >= 0 && verifyEnd >= 0) {
1026
+ const verifySection = toolsContent.substring(verifyStart, verifyEnd);
1027
+ // 检查验证计划注册调用中是否使用了 validation_result
1028
+ const planRegMatch = verifySection.match(/register\(\{[^}]*验证计划:[^}]*\}\)/s);
1029
+ if (planRegMatch && planRegMatch[0].includes("source_type: \"validation_result\"")) {
1030
+ hardFail("CRITICAL_PROBLEM_PLAN_AS_RESULT", "problem-60: sf_verify 把验证计划注册为 validation_result", ["src/adapters/claude_code/tools.ts"], "problem-60", "验证计划冒充验证结果", "验证计划应注册为 task_context 类型");
1031
+ }
1032
+ }
1033
+ }
1034
+ // 静态检查:负向测试
1035
+ const testPath = path.join(rootDir, "tests/engine/evidence_grounding_contract.test.ts");
1036
+ if (!fs.existsSync(testPath)) {
1037
+ hardFail("CRITICAL_PROBLEM_TEST_MISSING", "problem-60: 缺少负向测试文件", ["tests/engine/evidence_grounding_contract.test.ts"], "problem-60", "证据驱动机制缺少测试覆盖", "创建 evidence_grounding_contract.test.ts");
1038
+ }
1039
+ // 静态检查:知识规则
1040
+ const kaRulePath = path.join(rootDir, "templates/knowledge/rules/证据驱动与反幻觉规则.md");
1041
+ if (!fs.existsSync(kaRulePath)) {
1042
+ hardFail("CRITICAL_PROBLEM_ASSET_MISSING", "problem-60: 缺少知识规则文件 证据驱动与反幻觉规则.md", ["templates/knowledge/rules/证据驱动与反幻觉规则.md"], "problem-60", "证据驱动知识规则缺失", "创建知识规则文件");
1043
+ }
1044
+ // 静态检查:workflow_template
1045
+ const wfPath = path.join(rootDir, "src/adapters/shared/workflow_template.ts");
1046
+ const wfContent = safeRead(wfPath);
1047
+ if (!wfContent?.includes("wf-evidence-grounding")) {
1048
+ hardFail("CRITICAL_PROBLEM_TEMPLATE_MISSING", "problem-60: workflow_template.ts 缺少 wf-evidence-grounding 硬规则", ["src/adapters/shared/workflow_template.ts"], "problem-60", "工作流模板未包含证据驱动规则", "添加 wf-evidence-grounding 硬规则");
1049
+ }
1050
+ // 静态检查:TaskContext 类型必须有证据字段
1051
+ const typesPath = path.join(rootDir, "src/types.ts");
1052
+ const typesContent = safeRead(typesPath);
1053
+ if (typesContent && !typesContent.includes("evidence_matrix?:") && !typesContent.includes("evidence_gate_result?:")) {
1054
+ hardFail("CRITICAL_PROBLEM_TASKCTX_MISSING", "problem-60: TaskContext 缺少 evidence_matrix/evidence_gate_result 字段", ["src/types.ts"], "problem-60", "TaskContext 未保存证据结果", "添加 evidence_matrix 和 evidence_gate_result 字段");
1055
+ }
1056
+ // 静态检查:task_context.ts 必须有 setEvidenceGroundingResult 写入方法
1057
+ const tcPath = path.join(rootDir, "src/engine/task_context.ts");
1058
+ const tcContent = safeRead(tcPath);
1059
+ if (tcContent && !tcContent.includes("setEvidenceGroundingResult")) {
1060
+ hardFail("CRITICAL_PROBLEM_NO_WRITEBACK", "problem-60: task_context.ts 缺少 setEvidenceGroundingResult 写入方法", ["src/engine/task_context.ts"], "problem-60", "TaskContext 只有类型字段没有写入方法", "添加 setEvidenceGroundingResult 方法");
1061
+ }
1062
+ // 静态检查:tools.ts 主链路必须调用 setEvidenceGroundingResult
1063
+ if (toolsContent && !toolsContent.includes("setEvidenceGroundingResult")) {
1064
+ hardFail("CRITICAL_PROBLEM_NO_RUNTIME_WRITEBACK", "problem-60: tools.ts 未调用 setEvidenceGroundingResult 写回 TaskContext", ["src/adapters/claude_code/tools.ts"], "problem-60", "主链路不写回证据结果到 TaskContext", "在 sf_expand/sf_verify/sf_deliver 中调用 setEvidenceGroundingResult");
1065
+ }
1066
+ // 静态检查:tools.ts 不得出现 registry.query({}).map() 无差别证据绑定
1067
+ if (toolsContent) {
1068
+ const toolsLines = toolsContent.split("\n");
1069
+ for (let i = 0; i < toolsLines.length; i++) {
1070
+ if (/registry\.query\(\{\}\)\.map/.test(toolsLines[i])) {
1071
+ hardFail("CRITICAL_PROBLEM_INDISCRIMINATE_BINDING", `problem-60: tools.ts:${i + 1} 使用 registry.query({}).map() 无差别绑定证据到所有 claim`, ["src/adapters/claude_code/tools.ts"], "problem-60", "所有 registry 证据被无差别绑定到所有 claim,不区分语义", "按 claim 语义筛选 evidence_ids");
1072
+ }
1073
+ }
1074
+ }
1075
+ // 行为检查:setEvidenceGroundingResult 写入后 load 能读回
1076
+ try {
1077
+ const tcModule = await import(path.join(rootDir, "dist/engine/task_context.js"));
1078
+ const tmpStateDir = path.join(rootDir, ".soloforge", "state");
1079
+ const fsModule = await import("node:fs");
1080
+ if (!fsModule.existsSync(tmpStateDir)) {
1081
+ fsModule.mkdirSync(tmpStateDir, { recursive: true });
1082
+ }
1083
+ const tmpMgr = new tcModule.TaskContextManager(tmpStateDir);
1084
+ const tmpCtx = await tmpMgr.create("gate-evidence-writeback-test", "test");
1085
+ const testMatrix = {
1086
+ task_id: tmpCtx.task_id, claims: [], evidence: [],
1087
+ conflicts: [], unsupported_claims: ["test-claim"],
1088
+ risk_summary: { low: 0, medium: 0, high: 1, critical: 0 },
1089
+ created_at: new Date().toISOString(),
1090
+ };
1091
+ const testGate = {
1092
+ allowed: false, reason_zh: "测试", diagnostic_code: "SF-EVIDENCE-TEST",
1093
+ unsupported_claims: ["test-claim"], unresolved_conflicts: [],
1094
+ missing_evidence: [], risk_level: "high",
1095
+ requires_user_confirmation: [],
1096
+ };
1097
+ await tmpMgr.setEvidenceGroundingResult(tmpCtx.task_id, {
1098
+ evidence_matrix: testMatrix,
1099
+ evidence_gate_result: testGate,
1100
+ unsupported_claims: ["test-claim"],
1101
+ });
1102
+ const loaded = await tmpMgr.load(tmpCtx.task_id);
1103
+ if (!loaded?.evidence_matrix || !loaded?.evidence_gate_result) {
1104
+ hardFail("CRITICAL_PROBLEM_WRITEBACK_FAILED", "problem-60: setEvidenceGroundingResult 写入后 load 无法读回", ["src/engine/task_context.ts"], "problem-60", "TaskContext 写入方法不工作", "修复 setEvidenceGroundingResult 或 save/load");
1105
+ }
1106
+ if (loaded.evidence_gate_result?.allowed !== false) {
1107
+ hardFail("CRITICAL_PROBLEM_WRITEBACK_CORRUPT", "problem-60: setEvidenceGroundingResult 写入的 gate result 数据损坏", ["src/engine/task_context.ts"], "problem-60", "写入的 allowed=false 被读回为 true", "检查序列化逻辑");
1108
+ }
1109
+ // 清理测试任务
1110
+ try {
1111
+ fsModule.rmSync(path.join(tmpStateDir, `${tmpCtx.task_id}.json`), { force: true });
1112
+ }
1113
+ catch { }
1114
+ }
1115
+ catch (wbErr) {
1116
+ hardFail("CRITICAL_PROBLEM_WRITEBACK_ERROR", `problem-60: setEvidenceGroundingResult 行为检查失败: ${wbErr?.message ?? wbErr}`, ["src/engine/task_context.ts"], "problem-60", "TaskContext 写入方法不可用", "修复 import 或方法实现");
1117
+ }
1118
+ }
1119
+ _info(" problem-60 证据驱动消费验证完成");
768
1120
  }
769
1121
  // ── 7. Batch 问题文档格式一致性 ──
770
1122
  async function checkBatchIssueFormatConsistency(rootDir, hardFail, _info) {
@@ -783,13 +1135,13 @@ async function checkBatchIssueFormatConsistency(rootDir, hardFail, _info) {
783
1135
  hardFail("BATCH_ISSUE_FORMAT_INCONSISTENT", "loadBatchIssueDetails 导出未找到", ["scripts/batch_issue_details.mjs"], "构建系统", "共享解析脚本导出不正确", "修复脚本");
784
1136
  return;
785
1137
  }
786
- const expectedCounts = { 1: 19, 2: 12, 3: 9, 4: 13, 5: 5 };
1138
+ const expectedCounts = { 1: 19, 2: 12, 3: 9, 4: 13, 5: 6, 6: 2 };
787
1139
  const requiredPerProblemSections = [
788
1140
  "问题背景", "用户反馈 / 触发场景", "根因分析", "解决方案", "方案细节",
789
1141
  "硬规则", "非目标", "影响范围", "落地文件", "验收标准", "回归风险",
790
1142
  "与其他问题的关联", "发布门禁要求",
791
1143
  ];
792
- for (let batch = 1; batch <= 5; batch++) {
1144
+ for (let batch = 1; batch <= 6; batch++) {
793
1145
  const details = loadBatchIssueDetails(batch, rootDir);
794
1146
  if (!details.loaded) {
795
1147
  hardFail("BATCH_ISSUE_FORMAT_INCONSISTENT", `Batch${batch} 问题集未加载: ${details.error}`, [`docs/SoloForge-Batch${batch}问题集.md`], `Batch${batch}`, "旧 gate 只检查文档存在,不验证是否可解析", "第 3 步统一格式");
@@ -965,6 +1317,240 @@ function findFilesRecursive(dir, ext) {
965
1317
  }
966
1318
  return results;
967
1319
  }
1320
+ // ── Phase 10: P0/P1 知识资产 schema 完整性 ──
1321
+ async function checkKnowledgeAssetSchema(rootDir, hardFail, _info) {
1322
+ const matter = (await import("gray-matter")).default;
1323
+ const { validateKnowledgeAssetFrontmatter } = await import("./knowledge_asset_schema.js");
1324
+ const knowledgeDir = path.join(rootDir, "templates", "knowledge");
1325
+ if (!fs.existsSync(knowledgeDir))
1326
+ return;
1327
+ const mdFiles = findFilesRecursive(knowledgeDir, ".md");
1328
+ for (const filePath of mdFiles) {
1329
+ const raw = fs.readFileSync(filePath, "utf-8");
1330
+ const { data: frontmatter } = matter(raw);
1331
+ if (!frontmatter || Object.keys(frontmatter).length === 0)
1332
+ continue;
1333
+ if (!frontmatter.asset_kind)
1334
+ continue;
1335
+ const findings = validateKnowledgeAssetFrontmatter(frontmatter, filePath);
1336
+ for (const f of findings) {
1337
+ if (f.severity === "hard_fail") {
1338
+ hardFail(`KA_SCHEMA_${f.kind}`, f.message_zh, [filePath], f.asset_id, "旧 validate-release 不独立校验知识资产 schema", "补齐缺失的 frontmatter 字段");
1339
+ }
1340
+ }
1341
+ }
1342
+ }
1343
+ // ── Phase 11: engine console.log 检查 ──
1344
+ function checkEngineConsoleLog(rootDir, hardFail) {
1345
+ const targets = ["src/engine/", "src/index.ts"];
1346
+ for (const target of targets) {
1347
+ const fullTarget = path.join(rootDir, target);
1348
+ if (!fs.existsSync(fullTarget))
1349
+ continue;
1350
+ const isDir = fs.statSync(fullTarget).isDirectory();
1351
+ const files = isDir
1352
+ ? findFilesRecursive(fullTarget, ".ts")
1353
+ : [fullTarget];
1354
+ for (const file of files) {
1355
+ const content = fs.readFileSync(file, "utf-8");
1356
+ const lines = content.split("\n");
1357
+ for (let i = 0; i < lines.length; i++) {
1358
+ const line = lines[i];
1359
+ if (/^\s*\/\//.test(line))
1360
+ continue;
1361
+ if (/^\s*\*|^\s*\/\*/.test(line))
1362
+ continue;
1363
+ if (/"console\.log"|`console\.log`|'console\.log'|console\\.log/.test(line))
1364
+ continue;
1365
+ // 日志模块内部 stdout 封装允许 console.log
1366
+ if (/logger\.ts$/.test(file) && /^\s*console\.log\(/.test(line))
1367
+ continue;
1368
+ if (/console\.log\s*\(/.test(line)) {
1369
+ const rel = path.relative(rootDir, file);
1370
+ hardFail("ENGINE_CONSOLE_LOG", `${rel}:${i + 1} 使用 console.log(应使用 logger 或 console.error 写 stderr)`, [rel], "发布门禁 console 检查", "旧 gate 不检查 engine console.log", "替换为 logger 模块调用");
1371
+ }
1372
+ }
1373
+ }
1374
+ }
1375
+ }
1376
+ // ── Phase 12: 中文注释检查 ──
1377
+ function checkChineseComments(rootDir, hardFail) {
1378
+ const srcDir = path.join(rootDir, "src");
1379
+ if (!fs.existsSync(srcDir))
1380
+ return;
1381
+ const tsFiles = findFilesRecursive(srcDir, ".ts");
1382
+ for (const file of tsFiles) {
1383
+ const content = fs.readFileSync(file, "utf-8");
1384
+ const lines = content.split("\n");
1385
+ for (let i = 0; i < lines.length; i++) {
1386
+ const line = lines[i];
1387
+ if (!/^\s*\/\//.test(line))
1388
+ continue;
1389
+ if (/[一-龥]/.test(line))
1390
+ continue;
1391
+ // 跳过装饰分隔线
1392
+ if (/^\s*\/\/\s*[─═\-~=*#]+\s*$/.test(line))
1393
+ continue;
1394
+ // 跳过工具指令
1395
+ if (/@ts-|eslint|TODO|FIXME|NOTE|prettier|istanbul|c8/.test(line))
1396
+ continue;
1397
+ // 跳过机制 ID 标签
1398
+ if (/\/\/\s*──\s*\d+\./.test(line))
1399
+ continue;
1400
+ if (/\/\/\s*mc-[a-z]/.test(line))
1401
+ continue;
1402
+ // 跳过纯代码标识符
1403
+ if (/^\s*\/\/\s*[a-z][a-z0-9_.\/-]+\s*$/.test(line))
1404
+ continue;
1405
+ // 跳过大小标注
1406
+ if (/^\s*\/\/\s*\d+\s*(MB|KB|GB|ms|min|分钟|秒)/.test(line))
1407
+ continue;
1408
+ // 跳过技术术语注释
1409
+ if (/^\s*\/\/\s*[a-z_]+\.[a-z_]+/.test(line))
1410
+ continue;
1411
+ // 检查连续 4+ 字母
1412
+ if (/[a-zA-Z]{4,}/.test(line)) {
1413
+ const rel = path.relative(rootDir, file);
1414
+ hardFail("ENGLISH_COMMENT", `${rel}:${i + 1}: ${line.trim()}(应使用中文注释)`, [rel], "中文注释检查", "旧 gate 不检查中文注释", "将英文注释改为中文");
1415
+ }
1416
+ }
1417
+ }
1418
+ }
1419
+ // ── 13. 第五批文档↔roadmap↔scenario 一致性 ──
1420
+ async function checkLastBatchConsistency(rootDir, hardFail, _info) {
1421
+ // 动态导入避免循环依赖
1422
+ const roadmapPath = path.join(rootDir, "dist", "engine", "implementation_roadmap_registry.js");
1423
+ const scenarioPath = path.join(rootDir, "dist", "engine", "release_gate_scenario_registry.js");
1424
+ let listAllProblems;
1425
+ let listBatches;
1426
+ let RELEASE_GATE_SCENARIOS;
1427
+ let runAllReleaseGateScenarios;
1428
+ try {
1429
+ const roadmap = await import(roadmapPath);
1430
+ listAllProblems = roadmap.listAllProblems;
1431
+ listBatches = roadmap.listBatches;
1432
+ }
1433
+ catch {
1434
+ hardFail("LAST_BATCH_CONSISTENCY", "无法导入 implementation_roadmap_registry", ["src/engine/implementation_roadmap_registry.ts"], "末批一致性", "旧 gate 不检查 roadmap↔scenario 一致性", "先 build");
1435
+ return;
1436
+ }
1437
+ try {
1438
+ const scenario = await import(scenarioPath);
1439
+ RELEASE_GATE_SCENARIOS = scenario.RELEASE_GATE_SCENARIOS;
1440
+ runAllReleaseGateScenarios = scenario.runAllReleaseGateScenarios;
1441
+ }
1442
+ catch {
1443
+ hardFail("LAST_BATCH_CONSISTENCY", "无法导入 release_gate_scenario_registry", ["src/engine/release_gate_scenario_registry.ts"], "末批一致性", "旧 gate 不检查 roadmap↔scenario 一致性", "先 build");
1444
+ return;
1445
+ }
1446
+ // 1. 末批必须存在且包含 problem-55 到 problem-60
1447
+ const batches = listBatches();
1448
+ const lastBatch = batches.find((b) => b.batch_id === "batch-5");
1449
+ if (!lastBatch) {
1450
+ hardFail("LAST_BATCH_CONSISTENCY", "implementation_roadmap_registry 缺少 batch-5", ["src/engine/implementation_roadmap_registry.ts"], "末批一致性", "旧 gate 不检查末批是否存在于 roadmap", "新增 batch-5 并登记 problem-55 到 problem-60");
1451
+ return;
1452
+ }
1453
+ const expectedLastProblems = ["problem-55", "problem-56", "problem-57", "problem-58", "problem-59", "problem-60"];
1454
+ const missing = expectedLastProblems.filter((pid) => !lastBatch.included_problem_ids.includes(pid));
1455
+ if (missing.length > 0) {
1456
+ hardFail("LAST_BATCH_CONSISTENCY", `batch-5 缺少问题: ${missing.join(", ")}`, ["src/engine/implementation_roadmap_registry.ts"], "末批一致性", "旧 gate 不检查末批问题归属完整性", `将 ${missing.join(", ")} 加入 batch-5`);
1457
+ }
1458
+ // 2. problem-58 和 problem-60 不得在 batch-4
1459
+ const prevBatch = batches.find((b) => b.batch_id === "batch-4");
1460
+ if (prevBatch) {
1461
+ const misattrib = ["problem-58", "problem-60"].filter((pid) => prevBatch.included_problem_ids.includes(pid));
1462
+ if (misattrib.length > 0) {
1463
+ hardFail("LAST_BATCH_CONSISTENCY", `problem-58/60 错误归属到 batch-4: ${misattrib.join(", ")}`, ["src/engine/implementation_roadmap_registry.ts"], "末批一致性", "旧 gate 不检查问题是否被错误归入其他批次", "将 problem-58/60 从 batch-4 迁到 batch-5");
1464
+ }
1465
+ }
1466
+ // 3. 场景矩阵必须覆盖问题五十五到问题六十
1467
+ const scenarios = RELEASE_GATE_SCENARIOS;
1468
+ const allCoveredIssues = scenarios.flatMap((s) => s.covered_issues);
1469
+ const expectedIssueLabels = ["问题五十五", "问题五十六", "问题五十七", "问题五十八", "问题五十九", "问题六十"];
1470
+ const uncovered = expectedIssueLabels.filter((label) => !allCoveredIssues.includes(label));
1471
+ if (uncovered.length > 0) {
1472
+ hardFail("LAST_BATCH_CONSISTENCY", `场景矩阵未覆盖: ${uncovered.join(", ")}`, ["src/engine/release_gate_scenario_registry.ts"], "末批一致性", "旧 gate 不检查场景矩阵是否覆盖所有末批问题", `为 ${uncovered.join(", ")} 新增场景`);
1473
+ }
1474
+ // 4. 场景矩阵必须全部通过
1475
+ const results = runAllReleaseGateScenarios();
1476
+ const failedScenarios = results.filter((r) => !r.passed);
1477
+ if (failedScenarios.length > 0) {
1478
+ hardFail("LAST_BATCH_CONSISTENCY", `场景矩阵未全部通过: ${failedScenarios.map((r) => `${r.scenario_id}: ${r.failures.join("; ")}`).join(", ")}`, ["src/engine/release_gate_scenario_registry.ts"], "末批一致性", "旧 gate 不运行场景矩阵验证", "修复失败场景");
1479
+ }
1480
+ _info(" 第五批一致性校验通过");
1481
+ }
1482
+ // ── 14. 依赖漏洞扫描 ──
1483
+ function checkDependencyAudit(rootDir, hardFail, _info) {
1484
+ const reportPath = path.join(rootDir, ".soloforge", "advisory-report.json");
1485
+ if (!fs.existsSync(reportPath)) {
1486
+ hardFail("DEPENDENCY_AUDIT", "未找到依赖漏洞扫描报告 (.soloforge/advisory-report.json)", ["package.json"], "依赖健康", "旧 gate 不检查依赖漏洞", "运行 npm run audit-deps");
1487
+ return;
1488
+ }
1489
+ try {
1490
+ const report = JSON.parse(fs.readFileSync(reportPath, "utf-8"));
1491
+ if (!report.timestamp) {
1492
+ hardFail("DEPENDENCY_AUDIT", "漏洞扫描报告缺少时间戳", ["package.json"], "依赖健康", "旧 gate 不验证报告完整性", "重新运行 npm run audit-deps");
1493
+ return;
1494
+ }
1495
+ // 报告过期检查: 超过 24 小时视为过期
1496
+ const reportAge = Date.now() - new Date(report.timestamp).getTime();
1497
+ const maxAge = 24 * 60 * 60 * 1000;
1498
+ if (reportAge > maxAge) {
1499
+ hardFail("DEPENDENCY_AUDIT", `漏洞扫描报告已过期 (生成于 ${report.timestamp})`, ["package.json"], "依赖健康", "旧 gate 不检查报告时效", "重新运行 npm run audit-deps");
1500
+ return;
1501
+ }
1502
+ const blocked = report.blocked || [];
1503
+ if (blocked.length > 0) {
1504
+ const details = blocked.map((b) => `[${b.severity}] ${b.package}: ${b.title}`).join("; ");
1505
+ hardFail("DEPENDENCY_AUDIT", `发现 ${blocked.length} 个阻断级漏洞: ${details}`, ["package.json"], "依赖健康", "旧 gate 不扫描依赖漏洞", "npm audit fix 或升级依赖");
1506
+ return;
1507
+ }
1508
+ const total = report.vulnerability_summary?.total || 0;
1509
+ _info(` 依赖漏洞扫描通过: ${total} 个已知漏洞(无阻断级)`);
1510
+ }
1511
+ catch {
1512
+ hardFail("DEPENDENCY_AUDIT", "漏洞扫描报告格式无效", ["package.json"], "依赖健康", "旧 gate 不验证报告格式", "删除 .soloforge/advisory-report.json 并重新运行 npm run audit-deps");
1513
+ }
1514
+ }
1515
+ // ── 15. Batch6 架构决策与设计产物真实消费 ──
1516
+ async function checkBatch6DesignPath(rootDir, hardFail, _info) {
1517
+ const toolsText = safeRead(path.join(rootDir, "src", "adapters", "claude_code", "tools.ts")) ?? "";
1518
+ const cliText = safeRead(path.join(rootDir, "src", "bin", "soloforge.ts")) ?? "";
1519
+ const workflowText = safeRead(path.join(rootDir, "src", "adapters", "shared", "workflow_template.ts")) ?? "";
1520
+ if (!toolsText.includes("checkArchitectureDecisionWorkshopGate({") ||
1521
+ !toolsText.includes("projectContext: detectedArchitectureContext")) {
1522
+ hardFail("BATCH6_MAINLINE_MISSING", "问题六十一未接入 sf_expand 架构研讨阻断路径", ["src/adapters/claude_code/tools.ts"], "problem-61", "仅有合同或模板不能证明主链路消费", "在 sf_expand 真实路由调用架构研讨门");
1523
+ }
1524
+ if (!toolsText.includes("verifyDesignArtifactPack(projectPath, designPack)") ||
1525
+ !toolsText.includes("ctx.design_artifact_pack.status !== \"implementation_ready\"") ||
1526
+ !toolsText.includes("checkDesignArtifactWriteGate({ ctx, toolName: name, sideEffects: effectiveSideEffects })")) {
1527
+ hardFail("BATCH6_MAINLINE_MISSING", "问题六十二未同时接入真实 sf_verify、实现写入与 sf_deliver 就绪阻断", ["src/adapters/claude_code/tools.ts"], "problem-62", "仅有文档校验函数不能阻断用户编码/交付", "在验证、写入与交付路径消费设计产物包状态");
1528
+ }
1529
+ if (!cliText.includes("cmdAuditDesignArtifacts") ||
1530
+ !cliText.includes("cmdUpgradeDesignArtifacts") ||
1531
+ !cliText.includes("currentTask?.design_artifact_pack")) {
1532
+ hardFail("BATCH6_USER_CLI_MISSING", "问题六十二缺少用户 CLI 审计/升级或 Claude Code 写入 hook 阻断路径", ["src/bin/soloforge.ts"], "problem-62", "MCP 内部调用不能覆盖用户现有文档升级与直接 Edit/Write 路径", "接入 audit/upgrade CLI 与 check-write 设计产物门");
1533
+ }
1534
+ if (!workflowText.includes("wf-architecture-workshop-first") || !workflowText.includes("wf-design-artifact-pack")) {
1535
+ hardFail("BATCH6_USER_INJECTION_MISSING", "用户项目工作流模板未注入 Batch6 薄硬协议", ["src/adapters/shared/workflow_template.ts"], "problem-61/problem-62", "运行时有门但用户不可预期会造成体验断裂", "向 workflow template 注入硬规则");
1536
+ }
1537
+ try {
1538
+ const workshop = await import(path.join(rootDir, "dist", "engine", "architecture_decision_workshop.js"));
1539
+ const designPack = await import(path.join(rootDir, "dist", "engine", "design_artifact_pack.js"));
1540
+ const draft = workshop.createArchitectureDecisionWorkshop("release-batch6", "new_system");
1541
+ if (workshop.evaluateArchitectureDecisionWorkshop(draft).allowed) {
1542
+ hardFail("BATCH6_BEHAVIOR_FALSE_PASS", "问题六十一未确认六域的草稿错误放行", ["src/engine/architecture_decision_workshop.ts"], "problem-61", "必须有负向行为证据", "修复研讨生成门");
1543
+ }
1544
+ const missingPackResult = designPack.verifyDesignArtifactPack(rootDir, designPack.createDesignArtifactPack("release-batch6"));
1545
+ if (missingPackResult.passed) {
1546
+ hardFail("BATCH6_BEHAVIOR_FALSE_PASS", "问题六十二缺少用户项目设计产物时错误放行", ["src/engine/design_artifact_pack.ts"], "problem-62", "必须读取真实资产并阻断缺失", "修复设计产物复验门");
1547
+ }
1548
+ }
1549
+ catch (error) {
1550
+ hardFail("BATCH6_MODULE_LOAD_FAILED", `无法执行 Batch6 行为复验: ${error?.message ?? error}`, ["src/engine/architecture_decision_workshop.ts", "src/engine/design_artifact_pack.ts"], "Batch6", "模块不可执行", "修复构建或导出");
1551
+ }
1552
+ _info(" Batch6 架构决策与设计产物真实消费复验完成");
1553
+ }
968
1554
  // ── 主入口 ──
969
1555
  export async function runReleaseReadinessGate(rootDir) {
970
1556
  const hardFails = [];
@@ -1025,12 +1611,36 @@ export async function runReleaseReadinessGate(rootDir) {
1025
1611
  endPhase("Batch 问题文档格式一致性");
1026
1612
  // 8
1027
1613
  beginPhase("关键问题消费验证");
1028
- checkCriticalProblemConsumption(rootDir, hardFail, _info);
1614
+ await checkCriticalProblemConsumption(rootDir, hardFail, _info);
1029
1615
  endPhase("关键问题消费验证");
1030
1616
  // 9
1031
1617
  beginPhase("机制身份一致性");
1032
1618
  await checkMechanismIdentityConsistency(rootDir, hardFail, _info);
1033
1619
  endPhase("机制身份一致性");
1620
+ // 10: P0/P1 知识资产 schema 完整性
1621
+ beginPhase("P0/P1 知识资产 schema");
1622
+ await checkKnowledgeAssetSchema(rootDir, hardFail, _info);
1623
+ endPhase("P0/P1 知识资产 schema");
1624
+ // 11: console.log 检查
1625
+ beginPhase("engine console.log 检查");
1626
+ checkEngineConsoleLog(rootDir, hardFail);
1627
+ endPhase("engine console.log 检查");
1628
+ // 12: 中文注释检查
1629
+ beginPhase("中文注释检查");
1630
+ checkChineseComments(rootDir, hardFail);
1631
+ endPhase("中文注释检查");
1632
+ // 13: 第五批文档↔roadmap↔scenario 一致性
1633
+ beginPhase("第五批一致性校验");
1634
+ await checkLastBatchConsistency(rootDir, hardFail, _info);
1635
+ endPhase("第五批一致性校验");
1636
+ // 14: 依赖漏洞扫描(在 console.error 恢复前执行以避免干扰)
1637
+ beginPhase("依赖漏洞扫描");
1638
+ checkDependencyAudit(rootDir, hardFail, _info);
1639
+ endPhase("依赖漏洞扫描");
1640
+ // 15: Batch6 新增真实用户路径
1641
+ beginPhase("Batch6 架构决策与设计产物真实消费");
1642
+ await checkBatch6DesignPath(rootDir, hardFail, _info);
1643
+ endPhase("Batch6 架构决策与设计产物真实消费");
1034
1644
  // 恢复 console.error 和日志器
1035
1645
  console.error = origConsoleError;
1036
1646
  resetLogger();