cann-workbench 0.0.0-stage → 0.0.2-alpha

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 (408) hide show
  1. package/README.md +183 -2
  2. package/THIRD_PARTY_NOTICES.md +85 -0
  3. package/cordis.patch.yml +3 -0
  4. package/doctor/LICENSE +202 -0
  5. package/doctor/NOTICE +12 -0
  6. package/doctor/README.md +18 -0
  7. package/lib/client.js +94437 -0
  8. package/lib/index.d.ts +722 -0
  9. package/lib/index.js +33711 -0
  10. package/locale/en.json +6 -0
  11. package/locale/zh.json +6 -0
  12. package/package.json +171 -4
  13. package/skills/asc-tools/tool-ops-tune/INSTALL.md +52 -0
  14. package/skills/asc-tools/tool-ops-tune/LICENSE +38 -0
  15. package/skills/asc-tools/tool-ops-tune/README.md +167 -0
  16. package/skills/asc-tools/tool-ops-tune/SKILL.md +93 -0
  17. package/skills/asc-tools/tool-ops-tune/agent/AGENTS.md +195 -0
  18. package/skills/asc-tools/tool-ops-tune/agent/agents/perf-implementer.md +68 -0
  19. package/skills/asc-tools/tool-ops-tune/agent/agents/perf-reviewer.md +86 -0
  20. package/skills/asc-tools/tool-ops-tune/agent/workflows/task-prompts.md +362 -0
  21. package/skills/asc-tools/tool-ops-tune/agent/workflows/troubleshooting.md +43 -0
  22. package/skills/asc-tools/tool-ops-tune/docs/figures/opstune-architecture.png +0 -0
  23. package/skills/asc-tools/tool-ops-tune/docs/figures/opstune-architecture.svg +253 -0
  24. package/skills/asc-tools/tool-ops-tune/docs/ops-tune-design.md +404 -0
  25. package/skills/asc-tools/tool-ops-tune/docs//347/224/250/344/276/213/346/236/204/345/273/272.md +730 -0
  26. package/skills/asc-tools/tool-ops-tune/docs//347/237/245/350/257/206/345/272/223/350/247/204/350/214/203.md +103 -0
  27. package/skills/asc-tools/tool-ops-tune/evals/evals.json +242 -0
  28. package/skills/asc-tools/tool-ops-tune/ops-collect/SKILL.md +146 -0
  29. package/skills/asc-tools/tool-ops-tune/ops-collect/references/tool-routing.md +86 -0
  30. package/skills/asc-tools/tool-ops-tune/ops-collect/scripts/collect_board.sh +458 -0
  31. package/skills/asc-tools/tool-ops-tune/ops-collect/scripts/collect_cases.py +368 -0
  32. package/skills/asc-tools/tool-ops-tune/ops-collect/scripts/collect_sim.sh +134 -0
  33. package/skills/asc-tools/tool-ops-tune/ops-collect/scripts/csv_to_db.py +314 -0
  34. package/skills/asc-tools/tool-ops-tune/ops-collect/scripts/db_bench.py +545 -0
  35. package/skills/asc-tools/tool-ops-tune/ops-collect/scripts/facts_bridge.py +1102 -0
  36. package/skills/asc-tools/tool-ops-tune/ops-collect/scripts/isolation_test.py +452 -0
  37. package/skills/asc-tools/tool-ops-tune/ops-collect/scripts/jsonl_to_cases.py +163 -0
  38. package/skills/asc-tools/tool-ops-tune/ops-family/SKILL.md +76 -0
  39. package/skills/asc-tools/tool-ops-tune/ops-family/references/broadcast/advanced_tiling.md +92 -0
  40. package/skills/asc-tools/tool-ops-tune/ops-family/references/broadcast/broadcast_design.md +160 -0
  41. package/skills/asc-tools/tool-ops-tune/ops-family/references/broadcast/code/broadcast_add_kernel.cpp +126 -0
  42. package/skills/asc-tools/tool-ops-tune/ops-family/references/broadcast/code/broadcast_add_tiling.cpp +144 -0
  43. package/skills/asc-tools/tool-ops-tune/ops-family/references/broadcast/code/broadcast_tiling_common.h +401 -0
  44. package/skills/asc-tools/tool-ops-tune/ops-family/references/broadcast/code/onedim_add_kernel.cpp +107 -0
  45. package/skills/asc-tools/tool-ops-tune/ops-family/references/broadcast/code/onedim_add_tiling.cpp +64 -0
  46. package/skills/asc-tools/tool-ops-tune/ops-family/references/broadcast/datacopypad_design.md +46 -0
  47. package/skills/asc-tools/tool-ops-tune/ops-family/references/broadcast/guide.md +14 -0
  48. package/skills/asc-tools/tool-ops-tune/ops-family/references/broadcast/nddma_design.md +53 -0
  49. package/skills/asc-tools/tool-ops-tune/ops-family/references/broadcast/onedim_design.md +114 -0
  50. package/skills/asc-tools/tool-ops-tune/ops-family/references/broadcast/ub_broadcast_design.md +67 -0
  51. package/skills/asc-tools/tool-ops-tune/ops-family/references/common/datacopy_optimization_design.md +351 -0
  52. package/skills/asc-tools/tool-ops-tune/ops-family/references/common/index.md +9 -0
  53. package/skills/asc-tools/tool-ops-tune/ops-family/references/common/tail_block_design.md +268 -0
  54. package/skills/asc-tools/tool-ops-tune/ops-family/references/common/timing_harness/index.md +38 -0
  55. package/skills/asc-tools/tool-ops-tune/ops-family/references/common/timing_harness/timing_harness_aclrt_event.cpp +199 -0
  56. package/skills/asc-tools/tool-ops-tune/ops-family/references/common/timing_harness/timing_harness_torch_event.py +130 -0
  57. package/skills/asc-tools/tool-ops-tune/ops-family/references/common/ub_resident_design.md +342 -0
  58. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/guide.md +69 -0
  59. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/index.md +4 -0
  60. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_base.template +81 -0
  61. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_big_dim.template +217 -0
  62. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_cut_one_axis.template +336 -0
  63. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_cut_two_axis.template +781 -0
  64. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_n_last.template +340 -0
  65. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_small_shape.template +321 -0
  66. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_tensor_move.template +102 -0
  67. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_transdata_5hd.template +480 -0
  68. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_transdata_5hd_021axis.template +533 -0
  69. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/templates/dav3510/transpose_with_gather.template +688 -0
  70. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/templates/transpose_tiling_data.template +192 -0
  71. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/transpose_big_dim.md +220 -0
  72. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/transpose_cut_one_axis.md +175 -0
  73. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/transpose_cut_two_axis.md +177 -0
  74. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/transpose_fusion_design.md +398 -0
  75. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/transpose_gather.md +191 -0
  76. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/transpose_n_last.md +276 -0
  77. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/transpose_small_shape.md +315 -0
  78. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/transpose_tensor_move.md +203 -0
  79. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/transpose_tiling_data.md +176 -0
  80. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/transpose_vconv_021.md +206 -0
  81. package/skills/asc-tools/tool-ops-tune/ops-family/references/conversion/transpose_vconv_5hd.md +179 -0
  82. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/double_buffer_design.md +288 -0
  83. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/guide.md +46 -0
  84. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/index.md +10 -0
  85. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/CMakeLists.txt +131 -0
  86. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/README.md +55 -0
  87. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_extension/add_custom_torch.cpp +80 -0
  88. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_extension/ops.h +23 -0
  89. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_extension/register.cpp +30 -0
  90. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_host/add_custom.asc +149 -0
  91. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_host/data_utils.h +97 -0
  92. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_kernel/add_custom_kernel.asc +136 -0
  93. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/op_kernel/add_custom_tiling.h +31 -0
  94. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/run.sh +87 -0
  95. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/scripts/gen_data.py +70 -0
  96. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/scripts/golden.py +34 -0
  97. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/scripts/test_torch.py +99 -0
  98. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/add_custom/scripts/verify_result.py +56 -0
  99. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/templates/usage_guide.md +61 -0
  100. package/skills/asc-tools/tool-ops-tune/ops-family/references/elementwise/vector_efficiency_design.md +203 -0
  101. package/skills/asc-tools/tool-ops-tune/ops-family/references/fa/fa_mixed_kernel_design.md +174 -0
  102. package/skills/asc-tools/tool-ops-tune/ops-family/references/fa/fa_roofline_design.md +141 -0
  103. package/skills/asc-tools/tool-ops-tune/ops-family/references/fa/guide.md +87 -0
  104. package/skills/asc-tools/tool-ops-tune/ops-family/references/knowledge_gaps.json +56 -0
  105. package/skills/asc-tools/tool-ops-tune/ops-family/references/matmul/best-practices-guide.md +14 -0
  106. package/skills/asc-tools/tool-ops-tune/ops-family/references/matmul/fullload_design.md +344 -0
  107. package/skills/asc-tools/tool-ops-tune/ops-family/references/matmul/guide.md +52 -0
  108. package/skills/asc-tools/tool-ops-tune/ops-family/references/matmul/mte2_preload_design.md +320 -0
  109. package/skills/asc-tools/tool-ops-tune/ops-family/references/matmul/pingpong_design.md +254 -0
  110. package/skills/asc-tools/tool-ops-tune/ops-family/references/matmul/scale_coalescing_design.md +282 -0
  111. package/skills/asc-tools/tool-ops-tune/ops-family/references/matmul/streamk_design.md +374 -0
  112. package/skills/asc-tools/tool-ops-tune/ops-family/references/matmul/swat_design.md +423 -0
  113. package/skills/asc-tools/tool-ops-tune/ops-family/references/matmul/templates/matmul_basic_blaze.template +165 -0
  114. package/skills/asc-tools/tool-ops-tune/ops-family/references/matmul/templates/usage_guide.md +29 -0
  115. package/skills/asc-tools/tool-ops-tune/ops-family/references/mc2/best-practices-guide.md +43 -0
  116. package/skills/asc-tools/tool-ops-tune/ops-family/references/mc2/guide.md +42 -0
  117. package/skills/asc-tools/tool-ops-tune/ops-family/references/mc2/local_matmul_design.md +130 -0
  118. package/skills/asc-tools/tool-ops-tune/ops-family/references/mc2/pipeline_balancing_design.md +502 -0
  119. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/guide.md +178 -0
  120. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/dav310/kernel_utils.template +75 -0
  121. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ar_full_load.template +429 -0
  122. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ar_recompute.template +485 -0
  123. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ar_small_r.template +348 -0
  124. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ara_full_load.template +574 -0
  125. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ara_online.template +324 -0
  126. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_ara_recompute.template +436 -0
  127. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/dav310/softmax_v2_base.template +950 -0
  128. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/fused_attention_online_softmax_design.md +428 -0
  129. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ar_full_load.md +137 -0
  130. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ar_recompute.md +135 -0
  131. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ar_small_r.md +122 -0
  132. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ara_full_load.md +144 -0
  133. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ara_online.md +185 -0
  134. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_ara_recompute.md +163 -0
  135. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_tiling.template +460 -0
  136. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/softmax_v2_tiling_data.template +278 -0
  137. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/state_resident_design.md +337 -0
  138. package/skills/asc-tools/tool-ops-tune/ops-family/references/reduce/templates/usage_guide.md +253 -0
  139. package/skills/asc-tools/tool-ops-tune/ops-family/references/scalar/coding_principles.md +476 -0
  140. package/skills/asc-tools/tool-ops-tune/ops-family/references/scalar/conv_scalar.md +163 -0
  141. package/skills/asc-tools/tool-ops-tune/ops-family/references/scalar/guide.md +30 -0
  142. package/skills/asc-tools/tool-ops-tune/ops-family/references/simt/guide.md +91 -0
  143. package/skills/asc-tools/tool-ops-tune/ops-family/references/simt/optimization-guide.md +110 -0
  144. package/skills/asc-tools/tool-ops-tune/ops-family/references/sort/guide.md +83 -0
  145. package/skills/asc-tools/tool-ops-tune/ops-family/references/sort/radix_sort.md +354 -0
  146. package/skills/asc-tools/tool-ops-tune/ops-family/scripts/family_asset_audit.py +68 -0
  147. package/skills/asc-tools/tool-ops-tune/ops-family/scripts/tiling_candidates.py +419 -0
  148. package/skills/asc-tools/tool-ops-tune/ops-mechanism/SKILL.md +23 -0
  149. package/skills/asc-tools/tool-ops-tune/ops-mechanism/cases/ascendc/case_groupedmatmul_pipeline.md +23 -0
  150. package/skills/asc-tools/tool-ops-tune/ops-mechanism/cases/ascendc/case_triton_atomic_revert.md +19 -0
  151. package/skills/asc-tools/tool-ops-tune/ops-mechanism/cases/mc2/case_mc2_fusion.md +19 -0
  152. package/skills/asc-tools/tool-ops-tune/ops-mechanism/references/optimize/api-usage.md +70 -0
  153. package/skills/asc-tools/tool-ops-tune/ops-mechanism/references/optimize/ascendc-regbase-vf.md +45 -0
  154. package/skills/asc-tools/tool-ops-tune/ops-mechanism/references/optimize/ascendc-tiling.md +51 -0
  155. package/skills/asc-tools/tool-ops-tune/ops-mechanism/references/optimize/data-copy.md +67 -0
  156. package/skills/asc-tools/tool-ops-tune/ops-mechanism/references/optimize/index.md +45 -0
  157. package/skills/asc-tools/tool-ops-tune/ops-mechanism/references/optimize/mc2-balancing.md +77 -0
  158. package/skills/asc-tools/tool-ops-tune/ops-mechanism/references/optimize/mc2.md +103 -0
  159. package/skills/asc-tools/tool-ops-tune/ops-mechanism/references/optimize/memory-hierarchy.md +40 -0
  160. package/skills/asc-tools/tool-ops-tune/ops-mechanism/references/optimize/pipeline.md +95 -0
  161. package/skills/asc-tools/tool-ops-tune/ops-mechanism/scripts/case_backfill.py +170 -0
  162. package/skills/asc-tools/tool-ops-tune/ops-mechanism/scripts/log_gap.py +145 -0
  163. package/skills/asc-tools/tool-ops-tune/ops-mechanism/scripts/mc2_search.py +367 -0
  164. package/skills/asc-tools/tool-ops-tune/ops-report/SKILL.md +77 -0
  165. package/skills/asc-tools/tool-ops-tune/ops-verdict/evals/run_evals.py +963 -0
  166. package/skills/asc-tools/tool-ops-tune/ops-verdict/evals/smoke/install-hooks.sh +65 -0
  167. package/skills/asc-tools/tool-ops-tune/ops-verdict/evals/smoke/run_smoke.sh +535 -0
  168. package/skills/asc-tools/tool-ops-tune/ops-verdict/fixtures/core_tail_a5.csv +25 -0
  169. package/skills/asc-tools/tool-ops-tune/ops-verdict/fixtures/few_cores_a5.csv +5 -0
  170. package/skills/asc-tools/tool-ops-tune/ops-verdict/fixtures/mte2_bound_a2.csv +17 -0
  171. package/skills/asc-tools/tool-ops-tune/ops-verdict/fixtures/multi_kernel_mix_a5.csv +7 -0
  172. package/skills/asc-tools/tool-ops-tune/ops-verdict/fixtures/no_bound_a5.csv +9 -0
  173. package/skills/asc-tools/tool-ops-tune/ops-verdict/fixtures/serial_no_overlap_a2.csv +9 -0
  174. package/skills/asc-tools/tool-ops-tune/ops-verdict/fixtures/vec_bound_a5.csv +9 -0
  175. package/skills/asc-tools/tool-ops-tune/ops-verdict/references/io-contracts.md +94 -0
  176. package/skills/asc-tools/tool-ops-tune/ops-verdict/references/rule-schema.md +130 -0
  177. package/skills/asc-tools/tool-ops-tune/ops-verdict/references/scope-schema.md +61 -0
  178. package/skills/asc-tools/tool-ops-tune/ops-verdict/references/soc-spec.yaml +140 -0
  179. package/skills/asc-tools/tool-ops-tune/ops-verdict/rules/L0-instruction.yaml +67 -0
  180. package/skills/asc-tools/tool-ops-tune/ops-verdict/rules/L1-single-core.yaml +316 -0
  181. package/skills/asc-tools/tool-ops-tune/ops-verdict/rules/L2-inter-core.yaml +173 -0
  182. package/skills/asc-tools/tool-ops-tune/ops-verdict/rules/L3-inter-card.yaml +156 -0
  183. package/skills/asc-tools/tool-ops-tune/ops-verdict/scripts/batch_pipeline.py +466 -0
  184. package/skills/asc-tools/tool-ops-tune/ops-verdict/scripts/calibrate.py +249 -0
  185. package/skills/asc-tools/tool-ops-tune/ops-verdict/scripts/delta_compare.py +278 -0
  186. package/skills/asc-tools/tool-ops-tune/ops-verdict/scripts/render_html.py +304 -0
  187. package/skills/asc-tools/tool-ops-tune/ops-verdict/scripts/snapshot.py +200 -0
  188. package/skills/asc-tools/tool-ops-tune/ops-verdict/scripts/trace_bubble.py +331 -0
  189. package/skills/asc-tools/tool-ops-tune/ops-verdict/scripts/verdict.py +1094 -0
  190. package/skills/asc-tools/tool-ops-tune/scripts/diff_audit.py +281 -0
  191. package/skills/asc-tools/tool-precision-debug/LICENSE +38 -0
  192. package/skills/asc-tools/tool-precision-debug/README.md +190 -0
  193. package/skills/asc-tools/tool-precision-debug/scripts/install.sh +475 -0
  194. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/LICENSE +38 -0
  195. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/SKILL.md +136 -0
  196. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/evals/evals.json +932 -0
  197. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/diagnosis/baseline.md +69 -0
  198. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/diagnosis/checkpoint-design.md +82 -0
  199. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/diagnosis/dumptensor.md +83 -0
  200. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/diagnosis/hypothesis-experiment.md +114 -0
  201. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/diagnosis/index.md +20 -0
  202. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/diagnosis/localization.md +85 -0
  203. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/diagnosis/numerical-modeling.md +94 -0
  204. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/diagnosis/operator-modeling.md +116 -0
  205. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/diagnosis/progressive-error-analysis.md +86 -0
  206. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/diagnosis/reporting.md +140 -0
  207. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/diagnosis/reproducibility.md +121 -0
  208. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/diagnosis/semantic-bisection.md +72 -0
  209. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/diagnosis/sensitive-points.md +146 -0
  210. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/cases/fp16-promotion-boundary.md +46 -0
  211. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/cases/fused-rmsnorm-gelu-residual.md +162 -0
  212. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/cases/index.md +16 -0
  213. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/cases/integer-float-collision.md +44 -0
  214. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/cases/partial-statistics-merge.md +30 -0
  215. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/cases/softplus-v2-grad-family.md +156 -0
  216. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/cases/sync-dataflow-handshake.md +89 -0
  217. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/cases/tail-valid-region-state.md +30 -0
  218. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/cases/thnn-fused-gru-bias-reduction.md +73 -0
  219. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/index.md +34 -0
  220. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/accumulation-order.md +108 -0
  221. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/algorithm-parameter-contract.md +118 -0
  222. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/buffer-lifetime-alias.md +133 -0
  223. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/cast-rounding.md +76 -0
  224. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/complex-operator-boundary.md +48 -0
  225. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/data-movement-alignment.md +104 -0
  226. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/golden-host-contract.md +84 -0
  227. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/index-address-ownership.md +57 -0
  228. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/index.md +32 -0
  229. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/multicore-ownership.md +117 -0
  230. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/pipeline-sync-visibility.md +146 -0
  231. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/precision-mode-approximation.md +90 -0
  232. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/shape-boundary-contract.md +57 -0
  233. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/special-values.md +122 -0
  234. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/mechanisms/tiling-tail-state.md +146 -0
  235. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/operators/broadcast-transpose.md +64 -0
  236. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/operators/convolution.md +60 -0
  237. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/operators/dynamic-quant.md +47 -0
  238. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/operators/index.md +18 -0
  239. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/operators/matmul-mmad.md +131 -0
  240. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/operators/normalization.md +145 -0
  241. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/operators/reduction.md +167 -0
  242. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/operators/softplus-v2-grad.md +58 -0
  243. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/patterns/operators/sort-merge.md +65 -0
  244. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/tools/index.md +18 -0
  245. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/tools/kernel-debug-data.md +133 -0
  246. package/skills/asc-tools/tool-precision-debug/skills/tool-precision-debug/references/tools/msobjdump.md +150 -0
  247. package/skills/cann-doctor/SKILL.md +15 -0
  248. package/skills/catalog.json +79 -0
  249. package/skills/mattpocock/GLOSSARY.md +30 -0
  250. package/skills/mattpocock/LICENSE +21 -0
  251. package/skills/mattpocock/README.md +258 -0
  252. package/skills/mattpocock/SCOPE.md +35 -0
  253. package/skills/mattpocock/docs/agents/triage-labels.md +15 -0
  254. package/skills/mattpocock/docs/engineering/ask-matt.md +91 -0
  255. package/skills/mattpocock/docs/engineering/code-review.md +101 -0
  256. package/skills/mattpocock/docs/engineering/codebase-design.md +88 -0
  257. package/skills/mattpocock/docs/engineering/diagnosing-bugs.md +94 -0
  258. package/skills/mattpocock/docs/engineering/domain-modeling.md +86 -0
  259. package/skills/mattpocock/docs/engineering/grill-with-docs.md +82 -0
  260. package/skills/mattpocock/docs/engineering/implement-spec.md +86 -0
  261. package/skills/mattpocock/docs/engineering/implement.md +97 -0
  262. package/skills/mattpocock/docs/engineering/improve-codebase-architecture.md +113 -0
  263. package/skills/mattpocock/docs/engineering/pr.md +79 -0
  264. package/skills/mattpocock/docs/engineering/prototype.md +67 -0
  265. package/skills/mattpocock/docs/engineering/research.md +73 -0
  266. package/skills/mattpocock/docs/engineering/resolving-merge-conflicts.md +53 -0
  267. package/skills/mattpocock/docs/engineering/retro.md +81 -0
  268. package/skills/mattpocock/docs/engineering/setup-matt-pocock-skills.md +94 -0
  269. package/skills/mattpocock/docs/engineering/tdd.md +94 -0
  270. package/skills/mattpocock/docs/engineering/to-spec.md +81 -0
  271. package/skills/mattpocock/docs/engineering/to-tickets.md +99 -0
  272. package/skills/mattpocock/docs/engineering/triage.md +109 -0
  273. package/skills/mattpocock/docs/engineering/wayfinder.md +103 -0
  274. package/skills/mattpocock/docs/engineering/wizard.md +96 -0
  275. package/skills/mattpocock/docs/productivity/grill-me.md +76 -0
  276. package/skills/mattpocock/docs/productivity/grilling.md +87 -0
  277. package/skills/mattpocock/docs/productivity/handoff.md +76 -0
  278. package/skills/mattpocock/docs/productivity/teach.md +97 -0
  279. package/skills/mattpocock/docs/productivity/to-questionnaire.md +78 -0
  280. package/skills/mattpocock/docs/productivity/wait-what.md +36 -0
  281. package/skills/mattpocock/docs/productivity/writing-for-agents.md +70 -0
  282. package/skills/mattpocock/scripts/link-skills.sh +62 -0
  283. package/skills/mattpocock/scripts/list-skills.sh +7 -0
  284. package/skills/mattpocock/scripts/sync-plugin-version.mjs +41 -0
  285. package/skills/mattpocock/skills/deprecated/README.md +3 -0
  286. package/skills/mattpocock/skills/engineering/README.md +34 -0
  287. package/skills/mattpocock/skills/engineering/ask-matt/PHASE-BOUNDARIES.md +55 -0
  288. package/skills/mattpocock/skills/engineering/ask-matt/SKILL.md +97 -0
  289. package/skills/mattpocock/skills/engineering/ask-matt/agents/openai.yaml +5 -0
  290. package/skills/mattpocock/skills/engineering/code-review/SKILL.md +89 -0
  291. package/skills/mattpocock/skills/engineering/code-review/agents/openai.yaml +3 -0
  292. package/skills/mattpocock/skills/engineering/codebase-design/DEEPENING.md +37 -0
  293. package/skills/mattpocock/skills/engineering/codebase-design/DESIGN-IT-TWICE.md +44 -0
  294. package/skills/mattpocock/skills/engineering/codebase-design/SKILL.md +114 -0
  295. package/skills/mattpocock/skills/engineering/codebase-design/agents/openai.yaml +3 -0
  296. package/skills/mattpocock/skills/engineering/diagnosing-bugs/SKILL.md +138 -0
  297. package/skills/mattpocock/skills/engineering/diagnosing-bugs/agents/openai.yaml +3 -0
  298. package/skills/mattpocock/skills/engineering/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
  299. package/skills/mattpocock/skills/engineering/domain-modeling/ADR-FORMAT.md +47 -0
  300. package/skills/mattpocock/skills/engineering/domain-modeling/GLOSSARY-FORMAT.md +60 -0
  301. package/skills/mattpocock/skills/engineering/domain-modeling/SKILL.md +74 -0
  302. package/skills/mattpocock/skills/engineering/domain-modeling/agents/openai.yaml +3 -0
  303. package/skills/mattpocock/skills/engineering/grill-with-docs/SKILL.md +7 -0
  304. package/skills/mattpocock/skills/engineering/grill-with-docs/agents/openai.yaml +5 -0
  305. package/skills/mattpocock/skills/engineering/implement/SKILL.md +17 -0
  306. package/skills/mattpocock/skills/engineering/implement/agents/openai.yaml +5 -0
  307. package/skills/mattpocock/skills/engineering/implement-spec/SKILL.md +42 -0
  308. package/skills/mattpocock/skills/engineering/implement-spec/agents/openai.yaml +5 -0
  309. package/skills/mattpocock/skills/engineering/improve-codebase-architecture/HTML-REPORT.md +123 -0
  310. package/skills/mattpocock/skills/engineering/improve-codebase-architecture/SKILL.md +71 -0
  311. package/skills/mattpocock/skills/engineering/improve-codebase-architecture/agents/openai.yaml +5 -0
  312. package/skills/mattpocock/skills/engineering/pr/CREDITS.md +3 -0
  313. package/skills/mattpocock/skills/engineering/pr/SKILL.md +170 -0
  314. package/skills/mattpocock/skills/engineering/pr/agents/openai.yaml +3 -0
  315. package/skills/mattpocock/skills/engineering/prototype/LOGIC.md +67 -0
  316. package/skills/mattpocock/skills/engineering/prototype/SKILL.md +26 -0
  317. package/skills/mattpocock/skills/engineering/prototype/UI.md +112 -0
  318. package/skills/mattpocock/skills/engineering/prototype/agents/openai.yaml +3 -0
  319. package/skills/mattpocock/skills/engineering/research/SKILL.md +12 -0
  320. package/skills/mattpocock/skills/engineering/research/agents/openai.yaml +3 -0
  321. package/skills/mattpocock/skills/engineering/retro/SKILL.md +44 -0
  322. package/skills/mattpocock/skills/engineering/retro/agents/openai.yaml +5 -0
  323. package/skills/mattpocock/skills/engineering/setup-matt-pocock-skills/SKILL.md +120 -0
  324. package/skills/mattpocock/skills/engineering/setup-matt-pocock-skills/agents/openai.yaml +5 -0
  325. package/skills/mattpocock/skills/engineering/setup-matt-pocock-skills/domain.md +51 -0
  326. package/skills/mattpocock/skills/engineering/setup-matt-pocock-skills/issue-tracker-github.md +50 -0
  327. package/skills/mattpocock/skills/engineering/setup-matt-pocock-skills/issue-tracker-gitlab.md +46 -0
  328. package/skills/mattpocock/skills/engineering/setup-matt-pocock-skills/issue-tracker-local.md +30 -0
  329. package/skills/mattpocock/skills/engineering/setup-matt-pocock-skills/triage-labels.md +15 -0
  330. package/skills/mattpocock/skills/engineering/tdd/SKILL.md +38 -0
  331. package/skills/mattpocock/skills/engineering/tdd/agents/openai.yaml +3 -0
  332. package/skills/mattpocock/skills/engineering/tdd/mocking.md +59 -0
  333. package/skills/mattpocock/skills/engineering/tdd/tests.md +77 -0
  334. package/skills/mattpocock/skills/engineering/to-spec/SKILL.md +75 -0
  335. package/skills/mattpocock/skills/engineering/to-spec/agents/openai.yaml +5 -0
  336. package/skills/mattpocock/skills/engineering/to-tickets/SKILL.md +105 -0
  337. package/skills/mattpocock/skills/engineering/to-tickets/agents/openai.yaml +5 -0
  338. package/skills/mattpocock/skills/engineering/triage/AGENT-BRIEF.md +207 -0
  339. package/skills/mattpocock/skills/engineering/triage/OUT-OF-SCOPE.md +105 -0
  340. package/skills/mattpocock/skills/engineering/triage/SKILL.md +112 -0
  341. package/skills/mattpocock/skills/engineering/triage/agents/openai.yaml +5 -0
  342. package/skills/mattpocock/skills/engineering/wayfinder/SKILL.md +128 -0
  343. package/skills/mattpocock/skills/engineering/wayfinder/agents/openai.yaml +5 -0
  344. package/skills/mattpocock/skills/engineering/wizard/SKILL.md +44 -0
  345. package/skills/mattpocock/skills/engineering/wizard/agents/openai.yaml +3 -0
  346. package/skills/mattpocock/skills/engineering/wizard/template.sh +223 -0
  347. package/skills/mattpocock/skills/in-progress/README.md +17 -0
  348. package/skills/mattpocock/skills/in-progress/chief-of-staff/SKILL.md +75 -0
  349. package/skills/mattpocock/skills/in-progress/chief-of-staff/agents/openai.yaml +5 -0
  350. package/skills/mattpocock/skills/in-progress/claude-handoff/SKILL.md +18 -0
  351. package/skills/mattpocock/skills/in-progress/claude-handoff/agents/openai.yaml +5 -0
  352. package/skills/mattpocock/skills/in-progress/loop-me/SKILL.md +32 -0
  353. package/skills/mattpocock/skills/in-progress/loop-me/agents/openai.yaml +5 -0
  354. package/skills/mattpocock/skills/in-progress/setup-ts-deep-modules/SKILL.md +102 -0
  355. package/skills/mattpocock/skills/in-progress/setup-ts-deep-modules/agents/openai.yaml +5 -0
  356. package/skills/mattpocock/skills/in-progress/setup-ts-deep-modules/dependency-cruiser.config.cjs +95 -0
  357. package/skills/mattpocock/skills/in-progress/software-factory/EXAMPLE-TASKS.md +80 -0
  358. package/skills/mattpocock/skills/in-progress/software-factory/GIT-HOSTS.md +84 -0
  359. package/skills/mattpocock/skills/in-progress/software-factory/OBSERVABILITY-PLATFORMS.md +75 -0
  360. package/skills/mattpocock/skills/in-progress/software-factory/RUNNERS.md +94 -0
  361. package/skills/mattpocock/skills/in-progress/software-factory/SKILL.md +98 -0
  362. package/skills/mattpocock/skills/in-progress/software-factory/TICKET-TRACKERS.md +85 -0
  363. package/skills/mattpocock/skills/in-progress/writing-beats/SKILL.md +67 -0
  364. package/skills/mattpocock/skills/in-progress/writing-beats/agents/openai.yaml +5 -0
  365. package/skills/mattpocock/skills/in-progress/writing-fragments/SKILL.md +79 -0
  366. package/skills/mattpocock/skills/in-progress/writing-fragments/agents/openai.yaml +5 -0
  367. package/skills/mattpocock/skills/in-progress/writing-shape/SKILL.md +79 -0
  368. package/skills/mattpocock/skills/in-progress/writing-shape/agents/openai.yaml +5 -0
  369. package/skills/mattpocock/skills/misc/README.md +8 -0
  370. package/skills/mattpocock/skills/misc/git-guardrails-claude-code/SKILL.md +95 -0
  371. package/skills/mattpocock/skills/misc/git-guardrails-claude-code/agents/openai.yaml +3 -0
  372. package/skills/mattpocock/skills/misc/git-guardrails-claude-code/scripts/block-dangerous-git.sh +25 -0
  373. package/skills/mattpocock/skills/misc/migrate-to-shoehorn/SKILL.md +118 -0
  374. package/skills/mattpocock/skills/misc/migrate-to-shoehorn/agents/openai.yaml +3 -0
  375. package/skills/mattpocock/skills/misc/scaffold-exercises/SKILL.md +106 -0
  376. package/skills/mattpocock/skills/misc/scaffold-exercises/agents/openai.yaml +3 -0
  377. package/skills/mattpocock/skills/misc/setup-pre-commit/SKILL.md +91 -0
  378. package/skills/mattpocock/skills/misc/setup-pre-commit/agents/openai.yaml +3 -0
  379. package/skills/mattpocock/skills/productivity/README.md +20 -0
  380. package/skills/mattpocock/skills/productivity/grill-me/SKILL.md +7 -0
  381. package/skills/mattpocock/skills/productivity/grill-me/agents/openai.yaml +5 -0
  382. package/skills/mattpocock/skills/productivity/grilling/SKILL.md +30 -0
  383. package/skills/mattpocock/skills/productivity/grilling/agents/openai.yaml +3 -0
  384. package/skills/mattpocock/skills/productivity/handoff/SKILL.md +16 -0
  385. package/skills/mattpocock/skills/productivity/handoff/agents/openai.yaml +5 -0
  386. package/skills/mattpocock/skills/productivity/teach/GLOSSARY-FORMAT.md +35 -0
  387. package/skills/mattpocock/skills/productivity/teach/LEARNING-RECORD-FORMAT.md +46 -0
  388. package/skills/mattpocock/skills/productivity/teach/MISSION-FORMAT.md +31 -0
  389. package/skills/mattpocock/skills/productivity/teach/RESOURCES-FORMAT.md +32 -0
  390. package/skills/mattpocock/skills/productivity/teach/SKILL.md +140 -0
  391. package/skills/mattpocock/skills/productivity/teach/agents/openai.yaml +5 -0
  392. package/skills/mattpocock/skills/productivity/to-questionnaire/SKILL.md +54 -0
  393. package/skills/mattpocock/skills/productivity/to-questionnaire/agents/openai.yaml +5 -0
  394. package/skills/mattpocock/skills/productivity/wait-what/SKILL.md +7 -0
  395. package/skills/mattpocock/skills/productivity/wait-what/agents/openai.yaml +5 -0
  396. package/skills/mattpocock/skills/productivity/writing-for-agents/SKILL-MECHANICS.md +22 -0
  397. package/skills/mattpocock/skills/productivity/writing-for-agents/SKILL.md +81 -0
  398. package/skills/mattpocock/skills/productivity/writing-for-agents/agents/openai.yaml +3 -0
  399. package/skills/task-agents/operator-development/Agent.md +71 -0
  400. package/skills/task-agents/operator-development/skills.json +120 -0
  401. package/skills/task-agents/operator-development/stages.schema.json +532 -0
  402. package/skills/task-agents/performance-optimization/Agent.md +78 -0
  403. package/skills/task-agents/performance-optimization/skills.json +64 -0
  404. package/skills/task-agents/response-protocol.md +35 -0
  405. package/skills/task-agents/sidebar-contracts.schema.json +4168 -0
  406. package/skills/task-agents/sidebar-selection.schema.json +971 -0
  407. package/skills/task-agents/visuals/components.json +283 -0
  408. package/skills/task-agents/visuals/contracts.schema.json +3628 -0
@@ -0,0 +1,1094 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # ----------------------------------------------------------------------------------------------------------
4
+ # Copyright (c) 2026 Huawei Technologies Co., Ltd.
5
+ # This program is free software, you can redistribute it and/or modify it under the terms and conditions of
6
+ # CANN Open Software License Agreement Version 2.0 (the "License").
7
+ # Please refer to the License for details. You may not use this file except in compliance with the License.
8
+ # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
9
+ # INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
10
+ # See LICENSE in the root of the software repository for the full text of the License.
11
+ # ----------------------------------------------------------------------------------------------------------
12
+ """verdict.py — 算子调优判定引擎(规则-指标绑定契约 + 分层路由 + 反证 + 置信度)
13
+
14
+ 设计对齐(见 docs/ops-tune-design.md §3 核心设计决策 D1-D10):
15
+ - 对标业界领先 GPU Profiling 工具的 Guided Analysis:规则声明绑定指标,未采集则规则不触发
16
+ (机制上杜绝「指标没采却报规则」);REQUIRED 缺失 → rule: SKIPPED,OPTIONAL 缺失 → 降级不阻断(optional 仅用于反证;condition 内引用必须 required——加载校验 V4 强制)。
17
+ - 判定进脚本、解释进 LLM:本引擎输出结构化 verdict.json(机器可读契约),
18
+ Agent/LLM 只消费判定书做解释与编排,不做判定。
19
+ - 分层瀑布:L3 → L2 → L1 → L0 依序评估;L3 路由规则可禁用/改道下层规则(如 MTE2 污染)。
20
+ - 每条命中规则带反证(counter_evidence)与置信度;无证据不下结论。
21
+
22
+ 用法:
23
+ # 单核判定(PipeUtilization.csv)
24
+ python3 verdict.py --rules ../rules/L1-single-core.yaml --csv PipeUtilization.csv \
25
+ --scalar mte2_active_bw_pct_of_peak=82 --soc a5 -o verdict.json
26
+
27
+ # 多 kernel CSV(msprof op_summary 全量导出):必须 --kernel-name 过滤
28
+ python3 verdict.py --rules ../rules/L1-single-core.yaml --csv op_summary.csv \
29
+ --kernel-name my_custom_kernel --soc a5 -o verdict.json
30
+
31
+ # 核间判定(CSV + OpBasicInfo 衍生量)
32
+ python3 verdict.py --rules ../rules/L2-inter-core.yaml --csv PipeUtilization.csv \
33
+ --scalar physical_cores=48,block_dim=24,task_duration_us=210 -o verdict.json
34
+
35
+ # MC² 判定(隔离测试标量输入)
36
+ python3 verdict.py --rules ../rules/L3-inter-card.yaml \
37
+ --scalar t_comm_us=420,t_compute_us=880,mte2_ratio_full=62,mte2_ratio_pure=41 -o verdict.json
38
+
39
+ 输出(verdict.json 契约,report/agent 消费同一数据源):
40
+ {
41
+ "schema": "opstune.verdict/1.0",
42
+ "generated_at": "...", "rules_file": "...", "soc": "a5",
43
+ "facts": {...指标事实(含来源 CSV/行数)...},
44
+ "findings": [ {rule_id, name, severity, confidence, evidence, counter_evidence[],
45
+ speedup_range, mechanism_refs, ...} ],
46
+ "skipped": [ {rule_id, reason, missing} ],
47
+ "verdict": "NEEDS_OPTIMIZATION | NEAR_LIMIT | NO_BOUND_FOUND | INSUFFICIENT_DATA",
48
+ "headline": "...", "recommended_next": [...]
49
+ }
50
+
51
+ 阈值纪律:所有阈值带 threshold_source 溯源(实践沉淀 / 🟡 待标定)。
52
+ 变更规则或阈值必须先过 evals/run_evals.py(fixture CSV → 断言判定输出)全绿。
53
+ """
54
+
55
+ from __future__ import annotations
56
+
57
+ import argparse
58
+ import csv
59
+ import datetime
60
+ import json
61
+ import sys
62
+ from pathlib import Path
63
+
64
+ SCHEMA_VERDICT = "opstune.verdict/1.1" # 1.1:拆分 NO_BOUND_FOUND / NEAR_LIMIT
65
+
66
+
67
+ # --------------------------------------------------------------------------
68
+ # CSV 加载与指标事实构建
69
+ # --------------------------------------------------------------------------
70
+
71
+
72
+ def load_csv_rows(csv_path: str) -> list[dict]:
73
+ """读 CSV(兼容 utf-8-sig BOM 与脏数据,容错处理 msprof 导出的真实表头)。"""
74
+ rows = []
75
+ with open(csv_path, encoding="utf-8-sig", errors="replace") as f:
76
+ for row in csv.DictReader(f):
77
+ rows.append(row)
78
+ return rows
79
+
80
+
81
+ def load_db_rows(db_path: str, table: str) -> list[dict]:
82
+ """读 npu-compute summary.db 表 → 与 CSV 行同构的 dict 行(Roadmap #4 DB 输入)。
83
+
84
+ 列名规范化差异由 FieldUnitMap 还原:DB `aiv_time` → 键 `aiv_time(us)`——
85
+ 下游 pipe 指标/kernel 分组/规则求值零改动(同一批候选列命中)。
86
+ NULL → "NA" 字符串(与 CSV 侧 NA 语义对齐,parse_float 按缺失处理)。
87
+ DB 是同一次采集 CSV 的入库副本(npu-compute 双格式),数值口径等价;
88
+ 全表 dict 化形态 DB 并不占优(行对象化开销 > csv.DictReader,实测
89
+ 见 ops-collect db_bench W2)——DB 输入的价值在 facts 聚合下推与多表查询。
90
+ """
91
+ import sqlite3
92
+
93
+ db = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
94
+ try:
95
+ tables = {
96
+ r[0]
97
+ for r in db.execute(
98
+ "SELECT name FROM sqlite_master WHERE type='table'"
99
+ ).fetchall()
100
+ }
101
+ if table not in tables:
102
+ raise SystemExit(
103
+ f"ERROR: summary.db 无表 {table}(表集合 {sorted(tables)})。"
104
+ f"检查 --db-table 或改喂 Section CSV(--csv)。"
105
+ )
106
+ units = {}
107
+ if "FieldUnitMap" in tables:
108
+ units = dict(db.execute("SELECT field_name, unit FROM FieldUnitMap"))
109
+ cur = db.execute(f'SELECT * FROM "{table}" ORDER BY rowid')
110
+ names = [d[0] for d in cur.description]
111
+ keys = [f"{n}({units[n]})" if units.get(n) else n for n in names]
112
+ return [
113
+ {k: ("NA" if v is None else v) for k, v in zip(keys, row)}
114
+ for row in cur.fetchall()
115
+ ]
116
+ finally:
117
+ db.close()
118
+
119
+
120
+ def parse_float(value) -> float:
121
+ try:
122
+ return float(str(value).strip().replace("%", ""))
123
+ except (ValueError, AttributeError, TypeError):
124
+ return None # 缺失值:None 而非 0.0 —— 0.0 会污染 mean 与条件判定
125
+
126
+
127
+ def ratio_to_pct(v: float) -> float:
128
+ """兼容 0~1 比例与 0~100 百分数两种版本字段。"""
129
+ if v is None:
130
+ return None
131
+ return v * 100 if 0 <= v <= 1.5 else v
132
+
133
+
134
+ def first_present(row: dict, columns: list) -> float:
135
+ for col in columns:
136
+ if col in row and str(row.get(col, "")).strip() not in ("", "N/A", "NA", "-"):
137
+ v = parse_float(row[col])
138
+ if v is not None:
139
+ return v
140
+ return None
141
+
142
+
143
+ def pipe_metrics_from_rows(rows: list[dict], spec: dict) -> dict:
144
+ """从 PipeUtilization 行构建 pipe 指标:per-row 取候选列最大值(aic/aiv 双列兼容),
145
+ 跨行 mean / max 双口径 —— 判定用 mean,max 仅识别长尾(单核峰值不代表全 kernel)。"""
146
+ out = {}
147
+ pipe_cols = []
148
+ for name, m in spec.items():
149
+ if m.get("source") != "pipe":
150
+ continue
151
+ pipe_cols.append((name, m))
152
+ per_row = [first_present(r, m["columns"]) for r in rows]
153
+ per_row = [
154
+ ratio_to_pct(v)
155
+ if m.get("normalize") == "ratio_to_pct" and v is not None
156
+ else v
157
+ for v in per_row
158
+ ]
159
+ valid = [v for v in per_row if v is not None]
160
+ out[f"{name}"] = {
161
+ "mean": (sum(valid) / len(valid)) if valid else None,
162
+ "max": max(valid) if valid else None,
163
+ "rows_present": len(valid),
164
+ "rows_total": len(rows),
165
+ }
166
+ # 衍生量:主导 pipe / pipe 求和(串行指纹)——仅聚合 mean 语义
167
+ means = {
168
+ n: out[n]["mean"]
169
+ for n, _ in pipe_cols
170
+ if out.get(n, {}).get("mean") is not None
171
+ }
172
+ if means:
173
+ out["__max_pipe_mean"] = {
174
+ "mean": max(means.values()),
175
+ "source": "derived:max_of_pipe_means",
176
+ }
177
+ out["__max_pipe_name"] = {
178
+ "mean_name": max(means, key=means.get),
179
+ "source": "derived",
180
+ }
181
+ out["__pipe_sum_mean"] = {
182
+ "mean": sum(means.values()),
183
+ "source": "derived:sum_of_pipe_means",
184
+ }
185
+ return out
186
+
187
+
188
+ def _rows_core_kind(rows: list[dict]) -> str | None:
189
+ """从 sub_block_id 判活跃行集的核型(null=CSV 无该列或未知前缀)。
190
+
191
+ row_count 是「活跃子块行数」(Vec/Cube 行都计入)——row_kind 把行集核型
192
+ 显式化,供 occupancy 分母交叉审计(physical_cores 须与行集同维:cube
193
+ 行集配 AIC 数、vec 行集配 AIV 数;facts_bridge 按同款判别选分母)。
194
+ 纯 Cube 行(cube 前缀,忽略大小写)→ "cube";含 Vec 行 → "vector"。
195
+ """
196
+ if not rows or "sub_block_id" not in rows[0]:
197
+ return None
198
+ kinds = set()
199
+ for r in rows:
200
+ sb = str(r.get("sub_block_id") or "").strip().lower()
201
+ if sb.startswith("cube"):
202
+ kinds.add("cube")
203
+ elif sb.startswith("vec"):
204
+ kinds.add("vector")
205
+ if kinds == {"cube"}:
206
+ return "cube"
207
+ if "vector" in kinds:
208
+ return "vector"
209
+ return None
210
+
211
+
212
+ def time_metrics_from_rows(rows: list[dict]) -> dict:
213
+ """逐核耗时(核间层):aiv_time/aic_time 双列兼容,取大者为该核主体时间。
214
+
215
+ row_count 语义 = 活跃子块行数(Vec/Cube 行都计入,不滤 sub_block_id);
216
+ row_kind 是行集核型审计字段(occupancy 分母同维检查的真源)。
217
+ """
218
+ times = []
219
+ for r in rows:
220
+ aiv = parse_float(r.get("aiv_time(us)"))
221
+ aic = parse_float(r.get("aic_time(us)"))
222
+ cand = [v for v in (aiv, aic) if v is not None]
223
+ if cand:
224
+ times.append(max(cand))
225
+ if not times:
226
+ return {}
227
+ mean = sum(times) / len(times)
228
+ return {
229
+ "row_count": {"value": float(len(times))},
230
+ "row_kind": {"value": _rows_core_kind(rows)},
231
+ "time_mean_us": {"value": mean},
232
+ "time_max_us": {"value": max(times)},
233
+ "time_min_us": {"value": min(times)},
234
+ "dominant_time_us": {
235
+ "value": mean
236
+ }, # 逐核均值(与 yaml 描述一致;L2_HEAD_OVERHEAD 消费)
237
+ "__tail_ratio": {"value": (max(times) / mean) if mean > 0 else None},
238
+ "__imbalance_pct": {
239
+ "value": ((max(times) - min(times)) / max(times) * 100)
240
+ if max(times) > 0
241
+ else None
242
+ },
243
+ "__two_cluster_gap_pct": {"value": _two_cluster_gap(times)},
244
+ }
245
+
246
+
247
+ def _two_cluster_gap(times: list[float]):
248
+ """两簇检测:前后半段核均值差距 %(NUMA/L2 slice 负载偏斜提示)。"""
249
+ if len(times) < 4:
250
+ return None
251
+ half = len(times) // 2
252
+ m1, m2 = sum(times[:half]) / half, sum(times[half:]) / (len(times) - half)
253
+ if m2 <= 0:
254
+ return None
255
+ return abs(m1 - m2) / m2 * 100
256
+
257
+
258
+ def split_rows_by_kernel(rows: list[dict]) -> dict[str, list[dict]]:
259
+ """按 Op Name 列分组(多 kernel 混采防护)。
260
+
261
+ - 无 Op Name 列(逐核明细 CSV 形态,本仓 fixtures / PipeUtilization 常态)
262
+ → 单组 "<all>",保持向后兼容;
263
+ - 有 Op Name 列(msprof op_summary 全量导出形态)→ 按 kernel 名分组,
264
+ 调用方必须指定 --kernel-name,否则全行 mean/max 是跨 kernel 平均——
265
+ 数学上无意义且静默产出错误判定。
266
+ """
267
+ if not rows or "Op Name" not in rows[0]:
268
+ return {"<all>": rows}
269
+ groups: dict[str, list[dict]] = {}
270
+ for r in rows:
271
+ groups.setdefault(str(r.get("Op Name") or "").strip() or "<empty>", []).append(
272
+ r
273
+ )
274
+ return groups
275
+
276
+
277
+ # --------------------------------------------------------------------------
278
+ # 条件求值
279
+ # --------------------------------------------------------------------------
280
+
281
+
282
+ def get_metric_value(facts: dict, metrics_spec: dict, name: str, agg: str):
283
+ """取指标值。pipe 类返回 {mean,max} 聚合桶;scalar/derived 返回 {value 或 mean}。"""
284
+ if name not in facts:
285
+ return None
286
+ entry = facts[name]
287
+ if agg == "value":
288
+ if "value" in entry:
289
+ return entry["value"]
290
+ return entry.get("mean")
291
+ if agg == "mean":
292
+ return entry.get("mean", entry.get("value"))
293
+ if agg == "max":
294
+ return entry.get("max", entry.get("value"))
295
+ if agg == "rank":
296
+ # 该 pipe 在 group=pipe 集合中是否占比最大 → 1 最大
297
+ max_name = facts.get("__max_pipe_name", {}).get("mean_name")
298
+ return 1.0 if name == max_name else (0.0 if max_name else None)
299
+ return entry.get("mean")
300
+
301
+
302
+ def eval_leaf(
303
+ cond: dict, facts: dict, metrics_spec: dict, scalars: dict
304
+ ) -> bool | None:
305
+ """叶子条件:{metric, agg?, op, value}。返回 True/False/None(证据不足 → None,不可判)。"""
306
+ name = cond["metric"]
307
+ agg = cond.get("agg", "mean")
308
+ if name in metrics_spec and metrics_spec[name].get("source") == "scalar":
309
+ value = scalars.get(name)
310
+ else:
311
+ value = get_metric_value(facts, metrics_spec, name, agg)
312
+ # 复合值:{metric: X, factor: k} → 另一指标 × 系数(如 time_max > time_mean×1.25)
313
+ target = cond["value"]
314
+ if isinstance(target, dict):
315
+ t_name, t_factor = target["metric"], target.get("factor", 1.0)
316
+ if t_name in metrics_spec and metrics_spec[t_name].get("source") == "scalar":
317
+ t_val = scalars.get(t_name)
318
+ else:
319
+ t_val = get_metric_value(facts, metrics_spec, t_name, agg)
320
+ if t_val is None or value is None:
321
+ return None
322
+ target = t_val * t_factor
323
+ if value is None or target is None:
324
+ return None
325
+ op = cond["op"]
326
+ if op == "gt":
327
+ return value > target
328
+ if op == "gte":
329
+ return value >= target
330
+ if op == "lt":
331
+ return value < target
332
+ if op == "lte":
333
+ return value <= target
334
+ if op == "eq":
335
+ return value == target
336
+ if op == "between":
337
+ lo, hi = target if isinstance(target, (list, tuple)) else (target, target)
338
+ return lo <= value <= hi
339
+ if op == "gt_ratio":
340
+ # value 与 target 本身已是比值语义(如 __tail_ratio 直接与 1.25 比较)
341
+ return value > target
342
+ if op == "lt_ratio":
343
+ return value < target
344
+ raise ValueError(f"unknown op: {op}")
345
+
346
+
347
+ def eval_cond(cond, facts: dict, metrics_spec: dict, scalars: dict):
348
+ """递归求值 all/any/叶子。三值逻辑:None=证据不足。
349
+ all: 任一 False → False;有 None 无 False → None;否则 True。
350
+ any: 任一 True → True;有 None 无 True → None;否则 False。"""
351
+ if isinstance(cond, list):
352
+ cond = {"all": cond}
353
+ if "all" in cond:
354
+ saw_none = False
355
+ for sub in cond["all"]:
356
+ r = eval_cond(sub, facts, metrics_spec, scalars)
357
+ if r is False:
358
+ return False
359
+ if r is None:
360
+ saw_none = True
361
+ return None if saw_none else True
362
+ if "any" in cond:
363
+ saw_none = False
364
+ for sub in cond["any"]:
365
+ r = eval_cond(sub, facts, metrics_spec, scalars)
366
+ if r is True:
367
+ return True
368
+ if r is None:
369
+ saw_none = True
370
+ return None if saw_none else False
371
+ return eval_leaf(cond, facts, metrics_spec, scalars)
372
+
373
+
374
+ # --------------------------------------------------------------------------
375
+ # 规则求值
376
+ # --------------------------------------------------------------------------
377
+
378
+
379
+ def required_metrics_present(rule: dict, facts: dict, scalars: dict) -> list:
380
+ """返回缺失的 REQUIRED 指标(绑定契约:缺失 → SKIPPED,不触发不误报)。"""
381
+ missing = []
382
+ spec = rule.get("_metrics_spec", {})
383
+ for m in rule.get("metrics_required", []):
384
+ src = spec.get(m, {}).get("source", "pipe")
385
+ if src == "scalar":
386
+ if scalars.get(m) is None:
387
+ missing.append(m)
388
+ elif m not in facts or facts[m].get("mean", facts[m].get("value")) is None:
389
+ missing.append(m)
390
+ return missing
391
+
392
+
393
+ def severity_of(rule: dict, facts: dict, metrics_spec: dict, scalars: dict):
394
+ sev = rule.get("severity", {})
395
+ if "default" in sev and "metric" not in sev:
396
+ return sev["default"], ""
397
+ if "metric" in sev:
398
+ v = get_metric_value(facts, metrics_spec, sev["metric"], "mean")
399
+ if v is None:
400
+ v = scalars.get(sev["metric"])
401
+ if v is not None:
402
+ for band in sev.get("bands", []):
403
+ lo, hi = band.get("min"), band.get("max")
404
+ if lo is not None and v < lo:
405
+ continue
406
+ if hi is not None and v > hi:
407
+ continue
408
+ return band.get("level", "light"), band.get("note", "")
409
+ return sev.get("default", "light"), ""
410
+ return "light", ""
411
+
412
+
413
+ def eval_rule(
414
+ rule: dict, facts: dict, metrics_spec: dict, scalars: dict, disabled: set
415
+ ):
416
+ rid = rule["id"]
417
+ if rid in disabled:
418
+ return {
419
+ "rule_id": rid,
420
+ "status": "SKIPPED",
421
+ "reason": f"disabled by routing rule ({rid} 被上层路由禁用)",
422
+ }
423
+
424
+ missing = required_metrics_present(rule, facts, scalars)
425
+ if missing:
426
+ return {
427
+ "rule_id": rid,
428
+ "status": "SKIPPED",
429
+ "reason": f"REQUIRED 指标缺失: {', '.join(missing)}(绑定契约:未采集不判定)",
430
+ "missing": missing,
431
+ }
432
+
433
+ result = eval_cond(rule["condition"], facts, metrics_spec, scalars)
434
+ if result is None:
435
+ optional_missing = [
436
+ m
437
+ for m in rule.get("metrics_optional", [])
438
+ if m not in facts and scalars.get(m) is None
439
+ ]
440
+ return {
441
+ "rule_id": rid,
442
+ "status": "INSUFFICIENT_DATA",
443
+ "reason": "条件求值证据不足(存在 None 分支)",
444
+ "missing_optional": optional_missing,
445
+ }
446
+ if not result:
447
+ finding = {"rule_id": rid, "status": "NOT_HIT"}
448
+ w = rule.get("watch")
449
+ if w:
450
+ wv = eval_cond(w["condition"], facts, metrics_spec, scalars)
451
+ if wv is True:
452
+ finding["watch"] = w["note"]
453
+ return finding
454
+
455
+ # ---- 命中:组装 finding(判定书条目契约)----
456
+ sev, sev_note = severity_of(rule, facts, metrics_spec, scalars)
457
+ finding = {
458
+ "rule_id": rid,
459
+ "status": "HIT",
460
+ "name": rule.get("name", rid),
461
+ "layer": rule.get("_layer", ""),
462
+ "severity": sev,
463
+ "confidence": rule.get("confidence", "medium"),
464
+ "threshold_source": rule.get("threshold_source", ""),
465
+ "evidence": _evidence_text(rule, facts, metrics_spec, scalars),
466
+ "counter_evidence": _counter_evidence(rule, facts, metrics_spec, scalars),
467
+ "speedup_range": rule.get("speedup_range"),
468
+ "speedup_source": rule.get("speedup_source", ""),
469
+ "mechanism_refs": rule.get("mechanism_refs", []),
470
+ }
471
+ if sev_note:
472
+ finding["severity_note"] = sev_note
473
+ # 路由副作用:命中本规则可禁用其它规则 / 改道机制路由
474
+ routing = rule.get("routing")
475
+ if routing:
476
+ finding["routing"] = routing
477
+ return finding
478
+
479
+
480
+ def _evidence_text(rule, facts, metrics_spec, scalars) -> str:
481
+ parts = []
482
+ for m in rule.get("metrics_required", []):
483
+ v = get_metric_value(facts, metrics_spec, m, "mean")
484
+ if v is None:
485
+ v = scalars.get(m)
486
+ if v is not None:
487
+ parts.append(f"{m}={v:.1f}")
488
+ return ";".join(parts) if parts else "(derived condition)"
489
+
490
+
491
+ def _counter_evidence(rule, facts, metrics_spec, scalars) -> list:
492
+ """反证条目:条件为真时以 annotate 记录(供 LLM 解释与人工复核),
493
+ 不推翻判定 —— 判定只出自规则条件,反证是质量的第二道闸。"""
494
+ out = []
495
+ for ce in rule.get("counter_evidence", []):
496
+ r = eval_cond(
497
+ {
498
+ "metric": ce["condition"]["metric"],
499
+ "agg": ce["condition"].get("agg", "value"),
500
+ "op": ce["condition"]["op"],
501
+ "value": ce["condition"]["value"],
502
+ },
503
+ facts,
504
+ metrics_spec,
505
+ scalars,
506
+ )
507
+ if r is True:
508
+ out.append({"id": ce["id"], "note": ce["note"]})
509
+ elif r is None:
510
+ out.append(
511
+ {
512
+ "id": ce["id"],
513
+ "note": ce["note"] + "(反证指标缺失,未评估)",
514
+ "unevaluated": True,
515
+ }
516
+ )
517
+ return out
518
+
519
+
520
+ # --------------------------------------------------------------------------
521
+ # 规则包加载校验(schema 纪律机制化:违规启动即报错)
522
+ # --------------------------------------------------------------------------
523
+
524
+ # 引擎内置 derived 指标白名单(不声明在词汇表也可被规则引用)
525
+ DERIVED_WHITELIST = {
526
+ "__max_pipe_mean",
527
+ "__max_pipe_name",
528
+ "__pipe_sum_mean",
529
+ "__tail_ratio",
530
+ "__imbalance_pct",
531
+ "__two_cluster_gap_pct",
532
+ "r_value",
533
+ "__mte2_pollution_gap",
534
+ "__mte2_pure_ratio_pct",
535
+ "row_count",
536
+ "row_kind",
537
+ "time_mean_us",
538
+ "time_max_us",
539
+ "time_min_us",
540
+ "dominant_time_us",
541
+ "__occupancy_pct",
542
+ "__head_overhead_pct",
543
+ "__host_dispatch_pct",
544
+ }
545
+
546
+
547
+ def _leaves_of(cond) -> list:
548
+ """递归展开条件树的全部叶子(含 watch / counter_evidence 由调用方分别传入)。"""
549
+ out = []
550
+ if cond is None:
551
+ return out
552
+ if isinstance(cond, list):
553
+ for sub in cond:
554
+ out.extend(_leaves_of(sub))
555
+ return out
556
+ if isinstance(cond, dict):
557
+ if "metric" in cond and "op" in cond:
558
+ out.append(cond)
559
+ for key in ("all", "any"):
560
+ if key in cond:
561
+ out.extend(_leaves_of(cond[key]))
562
+ return out
563
+
564
+
565
+ def _leaf_metrics(cond) -> set:
566
+ """条件树引用的全部指标名(含复合 value 引用的 metric)。"""
567
+ names = set()
568
+ for leaf in _leaves_of(cond):
569
+ names.add(leaf["metric"])
570
+ if isinstance(leaf.get("value"), dict) and "metric" in leaf["value"]:
571
+ names.add(leaf["value"]["metric"])
572
+ return names
573
+
574
+
575
+ def validate_rules_pack(
576
+ pack: dict, rules_path: str, all_ids: set | None = None
577
+ ) -> list[str]:
578
+ """加载期校验,返回错误清单(非空 → 调用方报错退出)。
579
+
580
+ 校验项(rule-schema.md 已承诺而未实现的三条 + optional 语义强制):
581
+ V1 引用完整性:condition / watch / counter_evidence / severity 引用的指标
582
+ 必须在词汇表(metrics)或 derived 白名单内——未声明引用 = 配置错误;
583
+ V2 路由目标存在:routing.on_hit 的 disable_rule 目标必须存在于已知规则集
584
+ (all_ids 提供时按跨包全集校验;否则按本包 id 集合校验);
585
+ V3 同指标区间无重叠:同一指标的多条规则构成档位类判定(如 L3 R 值五档)
586
+ 时,区间不得重叠(消除「同一值双命中」类矛盾,F3 的机制化护栏);
587
+ V4 optional 语义:metrics_optional 中的指标禁止出现在 condition 中
588
+ (引擎对 condition 内 None 一律 INSUFFICIENT_DATA,不存在「可选指标
589
+ 缺失时跳过叶子」的降级求值——optional 仅用于反证,rule-schema.md 明确)。
590
+ """
591
+ errs = []
592
+ metrics = pack.get("metrics", {})
593
+ rules = pack.get("rules", [])
594
+ known = set(metrics) | DERIVED_WHITELIST
595
+ ids = all_ids if all_ids is not None else {r.get("id") for r in rules}
596
+
597
+ for rule in rules:
598
+ rid = rule.get("id", "<no-id>")
599
+ # V1 引用完整性
600
+ refs = _leaf_metrics(rule.get("condition"))
601
+ refs |= _leaf_metrics(
602
+ rule.get("watch", {}).get("condition") if rule.get("watch") else None
603
+ )
604
+ for ce in rule.get("counter_evidence", []):
605
+ refs |= _leaf_metrics(ce.get("condition"))
606
+ if isinstance(rule.get("severity"), dict) and "metric" in rule["severity"]:
607
+ refs.add(rule["severity"]["metric"])
608
+ undeclared = refs - known
609
+ if undeclared:
610
+ errs.append(
611
+ f"[V1] {rid}: 引用了未声明指标 {sorted(undeclared)}"
612
+ f"(词汇表 + derived 白名单均无;rule-schema.md:未声明引用=配置错误)"
613
+ )
614
+ # V4 optional 不进 condition
615
+ opt = set(rule.get("metrics_optional", []))
616
+ cond_refs = _leaf_metrics(rule.get("condition"))
617
+ bad_opt = opt & cond_refs
618
+ if bad_opt:
619
+ errs.append(
620
+ f"[V4] {rid}: optional 指标 {sorted(bad_opt)} 出现在 condition 中"
621
+ f"(optional 仅用于反证;condition 引用必须 required,缺失即 INSUFFICIENT_DATA)"
622
+ )
623
+ # V1b REQUIRED 引用同样校验(防拼写错误)
624
+ req_undeclared = set(rule.get("metrics_required", [])) - known
625
+ if req_undeclared:
626
+ errs.append(
627
+ f"[V1] {rid}: metrics_required 含未声明指标 {sorted(req_undeclared)}"
628
+ )
629
+ # V2 路由目标存在。on_hit 支持两种形态(rule-schema.md):
630
+ # 位置式列表 [disable_rule, <rule_id>](首元素为动作名,第二元素为目标)
631
+ # 映射式 dict {disable_rule: <rule_id>} 或字符串列表(每元素一个目标)
632
+ routing = rule.get("routing") or {}
633
+ on_hit = routing.get("on_hit", [])
634
+ targets = []
635
+ if isinstance(on_hit, list) and on_hit and on_hit[0] == "disable_rule":
636
+ targets = on_hit[1:] # 位置式:跳过动作名
637
+ elif isinstance(on_hit, list):
638
+ for act in on_hit:
639
+ if isinstance(act, dict) and "disable_rule" in act:
640
+ targets.append(act["disable_rule"])
641
+ elif isinstance(act, str):
642
+ targets.append(act)
643
+ for target in targets:
644
+ if target not in ids:
645
+ errs.append(
646
+ f"[V2] {rid}: routing.on_hit 禁用了不存在的规则 {target}(悬空路由)"
647
+ )
648
+
649
+ # V3 同指标区间无重叠(档位类判定)
650
+ per_metric: dict[str, list[tuple]] = {}
651
+ for rule in rules:
652
+ cond = rule.get("condition")
653
+ leaves = _leaves_of(cond)
654
+ if not leaves:
655
+ continue
656
+ # 仅当规则的全部叶子都引用同一指标且为区间形状(带数值边界的
657
+ # gt/gte/lt/lte/between)才视为该指标的档位类规则
658
+ metrics_in_cond = {leaf["metric"] for leaf in leaves}
659
+ if len(metrics_in_cond) != 1:
660
+ continue
661
+ m = leaves[0]["metric"]
662
+ lo = hi = None
663
+ shape_ok = True
664
+ for leaf in leaves:
665
+ op, val = leaf["op"], leaf["value"]
666
+ if op == "between" and isinstance(val, list) and len(val) == 2:
667
+ lo, hi = float(val[0]), float(val[1])
668
+ elif isinstance(val, (int, float)):
669
+ if op in ("gt", "gte") and lo is None:
670
+ lo = float(val)
671
+ elif op in ("lt", "lte") and hi is None:
672
+ hi = float(val)
673
+ else:
674
+ shape_ok = False
675
+ break
676
+ else:
677
+ shape_ok = False
678
+ break
679
+ if shape_ok and (lo is not None or hi is not None):
680
+ per_metric.setdefault(m, []).append((lo, hi, rule.get("id")))
681
+ for m, bands in per_metric.items():
682
+ bands.sort(key=lambda b: b[0] if b[0] is not None else float("-inf"))
683
+ for i in range(len(bands) - 1):
684
+ lo1, hi1, id1 = bands[i]
685
+ lo2, hi2, id2 = bands[i + 1]
686
+ if hi1 is not None and lo2 is not None and hi1 > lo2:
687
+ errs.append(
688
+ f"[V3] 指标 {m} 档位区间重叠:{id1}({lo1},{hi1}) 与 "
689
+ f"{id2}({lo2},{hi2})(同一值可双命中,机制方向可能矛盾)"
690
+ )
691
+ return errs
692
+
693
+
694
+ # --------------------------------------------------------------------------
695
+ # 主流程
696
+ # --------------------------------------------------------------------------
697
+
698
+
699
+ def load_rules(path: str) -> dict:
700
+ import yaml
701
+
702
+ with open(path, encoding="utf-8") as f:
703
+ return yaml.safe_load(f)
704
+
705
+
706
+ def _rule_default_severity(rule: dict) -> str:
707
+ """取规则 default severity(severity 为 {default: X} 或分档 dict)。"""
708
+ sev = rule.get("severity", {})
709
+ if isinstance(sev, dict):
710
+ return sev.get("default", "light")
711
+ return sev or "light"
712
+
713
+
714
+ def near_limit_threshold(all_hits_seeds: list[dict]) -> float | None:
715
+ """「接近上限」触发阈值(数据驱动)。
716
+
717
+ threshold = min(已加载规则中 default severity=critical 且 confidence=high 的
718
+ speedup_range 上界)——不硬编码 1.15,规则集演进自动联动(当前规则集下
719
+ L3_MC2_STRONG_COMPUTE [1.0,1.2] 成为 argmin)。无可参照规则时返回 None
720
+ (该分支退化为不可达,与「无此类规则」的规则集状态一致)。
721
+ """
722
+ bounds = [
723
+ r["speedup_range"][1]
724
+ for r in all_hits_seeds
725
+ if _rule_default_severity(r) == "critical"
726
+ and r.get("confidence") == "high"
727
+ and r.get("speedup_range")
728
+ ]
729
+ return min(bounds) if bounds else None
730
+
731
+
732
+ def headline_and_verdict(
733
+ findings: list, skipped: list, rule_seeds: list | None = None
734
+ ) -> tuple[str, str, list]:
735
+ hits = [f for f in findings if f.get("status") == "HIT"]
736
+ # NOT_HIT = 数据在、条件不成立(证据完整地排除了该规则)
737
+ evaluated = [s for s in skipped if s.get("status") == "NOT_HIT"]
738
+ if not hits:
739
+ if not evaluated:
740
+ # 没有任何规则被完整评估(全部因指标缺失跳过)→ 证据不足,不判 NEAR_LIMIT
741
+ return (
742
+ "证据不足,无法判定:全部规则因 REQUIRED 指标缺失被跳过(绑定契约:未采集不判定)",
743
+ "INSUFFICIENT_DATA",
744
+ ["按 skipped[].missing 提示补采指标后重跑 verdict.py"],
745
+ )
746
+ # 「未命中任何规则」≠「接近上限」:前者是「该换更深的指标」,后者是「该收手」
747
+ # ——拆分为独立 verdict 值 NO_BOUND_FOUND(schema 1.1)
748
+ return (
749
+ "未命中任何瓶颈规则(各 pipe 占比均衡且低于判定线)",
750
+ "NO_BOUND_FOUND",
751
+ ["评估是否已达性能目标;如仍需提升,采集 L0 源码级指标做深度分析"],
752
+ )
753
+ order = {"critical": 0, "moderate": 1, "light": 2}
754
+ conf = {"high": 0, "medium": 1, "low": 2}
755
+ hits.sort(
756
+ key=lambda f: (
757
+ order.get(f.get("severity"), 3),
758
+ conf.get(f.get("confidence"), 3),
759
+ )
760
+ )
761
+ top = hits[0]
762
+ headline = f"{top['name']}({top['severity']})" + (
763
+ f";另有 {len(hits) - 1} 项命中" if len(hits) > 1 else ""
764
+ )
765
+ # 接近上限判定(数据驱动阈值):唯一 critical+high 命中且其 speedup 上界 ≤ 阈值
766
+ # → NEAR_LIMIT 提示(阈值 = 全部 critical+high 规则上界的 min,见 near_limit_threshold)
767
+ threshold = near_limit_threshold(rule_seeds or findings)
768
+ if (
769
+ len(hits) == 1
770
+ and top["severity"] == "critical"
771
+ and top["confidence"] == "high"
772
+ and top.get("speedup_range")
773
+ and threshold is not None
774
+ and top["speedup_range"][1] <= threshold
775
+ ):
776
+ return (
777
+ headline,
778
+ "NEAR_LIMIT",
779
+ [
780
+ f"唯一瓶颈已接近理论上限(预估收益上界 {top['speedup_range'][1]}x,"
781
+ f"阈值 {threshold}x 由规则集 critical+high 上界派生),确认标尺后再投入"
782
+ ],
783
+ )
784
+ return (
785
+ headline,
786
+ "NEEDS_OPTIMIZATION",
787
+ [f"按 speedup_range 排序实施机制:{h['rule_id']}" for h in hits[:3]],
788
+ )
789
+
790
+
791
+ def main() -> int:
792
+ ap = argparse.ArgumentParser(
793
+ description="算子调优判定引擎(分层规则 + 绑定契约 + 反证)"
794
+ )
795
+ ap.add_argument(
796
+ "--rules",
797
+ required=True,
798
+ help="规则包 YAML(可逗号分隔多个,按层排序:L3,L2,L1,L0)",
799
+ )
800
+ ap.add_argument(
801
+ "--csv", default=None, help="PipeUtilization.csv(pipe/时间类指标源)"
802
+ )
803
+ ap.add_argument(
804
+ "--db",
805
+ default=None,
806
+ help="npu-compute summary.db(DB 输入,与 --csv 二选一;"
807
+ "Roadmap #4——列名规范化由 FieldUnitMap 自动还原)",
808
+ )
809
+ ap.add_argument(
810
+ "--db-table",
811
+ default="PipeUtilization",
812
+ help="--db 输入的指标表名(缺省 PipeUtilization)",
813
+ )
814
+ ap.add_argument(
815
+ "--kernel-name",
816
+ default=None,
817
+ help="目标 kernel 名(Op Name 列存在且多 kernel 时必填——G15 混采防护;"
818
+ "缺省且检测到多 kernel 时报错退出,不静默跨 kernel 平均)",
819
+ )
820
+ ap.add_argument(
821
+ "--scalar",
822
+ default="",
823
+ help="标量指标 key=value,key=value(bw 百分比/核数/隔离测试值等)",
824
+ )
825
+ ap.add_argument(
826
+ "--soc", default=None, help="SoC 标识(a2/a3/a5),用于规则包 soc 域过滤"
827
+ )
828
+ ap.add_argument("-o", "--output", required=True, help="verdict.json 输出路径")
829
+ args = ap.parse_args()
830
+
831
+ scalars = {}
832
+ if args.scalar:
833
+ for kv in args.scalar.split(","):
834
+ if "=" in kv:
835
+ k, v = kv.split("=", 1)
836
+ try:
837
+ scalars[k.strip()] = float(v)
838
+ except ValueError:
839
+ # 非数值标量(脏输入如 N/A):按缺失处理(None 语义 → 相关规则
840
+ # INSUFFICIENT/SKIPPED 降级),不进 facts 参与比较——
841
+ # 字符串进比较会 TypeError 崩溃)
842
+ print(
843
+ f"WARN: 标量 {k.strip()}={v!r} 非数值,按缺失处理(不参与判定)",
844
+ file=sys.stderr,
845
+ )
846
+ scalars[k.strip()] = None
847
+
848
+ if args.csv and args.db:
849
+ print(
850
+ "ERROR: --csv 与 --db 互斥(同一指标源选一个输入形态)",
851
+ file=sys.stderr,
852
+ )
853
+ return 1
854
+ if args.db:
855
+ if not Path(args.db).exists():
856
+ print(f"ERROR: --db 文件不存在: {args.db}", file=sys.stderr)
857
+ return 1
858
+ rows = load_db_rows(args.db, args.db_table)
859
+ print(
860
+ f"[db] {args.db}::{args.db_table}:{len(rows)} 行(DB 通道;列名按"
861
+ f" FieldUnitMap 还原单位后缀)",
862
+ file=sys.stderr,
863
+ )
864
+ else:
865
+ rows = load_csv_rows(args.csv) if args.csv else []
866
+ # ---- G15 kernel 归属校验:多 kernel CSV 混采防护(fail loud,不静默跨 kernel 平均)----
867
+ kernel_groups = split_rows_by_kernel(rows)
868
+ if len(kernel_groups) > 1:
869
+ available = ", ".join(sorted(kernel_groups))
870
+ if not args.kernel_name:
871
+ print(
872
+ f"ERROR: CSV 含 {len(kernel_groups)} 个 kernel(Op Name 多值:{available})。"
873
+ "全行 mean/max 是跨 kernel 平均,判定无意义——请用 --kernel-name 指定目标 kernel"
874
+ "(多 kernel 程序逐 kernel 判定),或改喂单 kernel 导出的 CSV。",
875
+ file=sys.stderr,
876
+ )
877
+ return 4
878
+ if args.kernel_name not in kernel_groups:
879
+ print(
880
+ f"ERROR: --kernel-name {args.kernel_name!r} 不在 CSV Op Name 集合中"
881
+ f"(实际:{available})。检查 kernel 名拼写或去掉过滤重采。",
882
+ file=sys.stderr,
883
+ )
884
+ return 4
885
+ rows = kernel_groups[args.kernel_name]
886
+ print(
887
+ f"[kernel] 按 Op Name={args.kernel_name} 过滤:{len(rows)} 行"
888
+ f"(共 {sum(len(v) for v in kernel_groups.values())} 行)",
889
+ file=sys.stderr,
890
+ )
891
+ all_findings, all_skipped = [], []
892
+ disabled: set = set()
893
+ facts_by_pack: dict = {} # pack_stem → facts(审计分层快照,F4)
894
+ rules_files = [p.strip() for p in args.rules.split(",") if p.strip()]
895
+ soc = args.soc
896
+
897
+ # ---- 加载校验(schema 纪律机制化:V1 引用完整性 / V2 悬空路由 / V3 区间重叠 / V4 optional)----
898
+ packs = [] # (path, pack) 供下方求值循环复用
899
+ all_rule_ids: set = set()
900
+ all_rule_seeds: list = [] # 规则种子(severity/confidence/speedup_range 供阈值派生)
901
+ for rf in rules_files:
902
+ pack = load_rules(rf)
903
+ packs.append((rf, pack))
904
+ all_rule_ids |= {r.get("id") for r in pack.get("rules", [])}
905
+ all_rule_seeds.extend(pack.get("rules", []))
906
+ # routing.on_hit 的 disable_rule 语义是跨包的(rule-schema.md):目标可能在未加载的
907
+ # 规则包中。校验全集 = 本次加载的包 + 同目录其余规则包(规则宇宙),防止单包运行时
908
+ # 误报「悬空」。
909
+ rule_universe = set(all_rule_ids)
910
+ for extra in Path(rules_files[0]).parent.glob("*.yaml"):
911
+ if str(extra) not in rules_files:
912
+ try:
913
+ extra_pack = load_rules(str(extra))
914
+ rule_universe |= {r.get("id") for r in extra_pack.get("rules", [])}
915
+ except Exception:
916
+ pass # 解析失败的旁路包不阻断本次校验(它自身被加载时才校验)
917
+ load_errors = []
918
+ for rf, pack in packs:
919
+ errs = validate_rules_pack(pack, rf, all_ids=rule_universe)
920
+ load_errors.extend(f"{Path(rf).name}: {e}" for e in errs)
921
+ if load_errors:
922
+ print("ERROR: 规则包加载校验失败(配置错误,拒绝求值):", file=sys.stderr)
923
+ for e in load_errors:
924
+ print(f" {e}", file=sys.stderr)
925
+ return 3
926
+
927
+ for rf, pack in packs:
928
+ if soc and pack.get("soc") and soc not in pack["soc"]:
929
+ all_skipped.append(
930
+ {
931
+ "rule_id": f"pack:{Path(rf).stem}",
932
+ "status": "SKIPPED",
933
+ "reason": f"规则包 soc 域 {pack['soc']} 不含 {soc}",
934
+ }
935
+ )
936
+ continue
937
+ metrics_spec = pack.get("metrics", {})
938
+ facts = {}
939
+ if rows:
940
+ facts.update(pipe_metrics_from_rows(rows, metrics_spec))
941
+ facts.update(time_metrics_from_rows(rows))
942
+ # 规则包循环内按包名累积 facts(全瀑布跑法下循环外只剩末包指标,
943
+ # L1 pipe 指标丢失,审计承诺失效;分层结构天然保留指标来源信息)
944
+ facts_by_pack[Path(rf).stem] = facts
945
+ # MC² 隔离实验标量 → 衍生指标(r_value 等)
946
+ if (
947
+ "t_comm_us" in scalars
948
+ and "t_compute_us" in scalars
949
+ and scalars.get("t_comm_us")
950
+ and scalars.get("t_compute_us")
951
+ ):
952
+ facts["r_value"] = {"value": scalars["t_compute_us"] / scalars["t_comm_us"]}
953
+ if "mte2_ratio_full" in scalars and "mte2_ratio_pure" in scalars:
954
+ full, pure = scalars["mte2_ratio_full"], scalars["mte2_ratio_pure"]
955
+ if full is not None and pure is not None:
956
+ facts["__mte2_pollution_gap"] = {"value": full - pure}
957
+ if full:
958
+ facts["__mte2_pure_ratio_pct"] = {"value": pure / full * 100}
959
+ # scalar 声明也并入 facts(供 get_metric_value 统一读取);非数值(None)不并入
960
+ for name, m in metrics_spec.items():
961
+ if (
962
+ m.get("source") == "scalar"
963
+ and name in scalars
964
+ and scalars[name] is not None
965
+ ):
966
+ facts[name] = {"value": scalars[name]}
967
+ # L2 derived:occupancy 与头开销(依赖 scalar 提供的 physical_cores / task_duration_us)
968
+ # — 三个 derived 此前从未计算:L2_HEAD_OVERHEAD 永 SKIPPED、L2_UNDERUTILIZATION
969
+ # 的 critical 档与头开销 critical 档是死代码
970
+ if "row_count" in facts and scalars.get("physical_cores"):
971
+ facts["__occupancy_pct"] = {
972
+ "value": facts["row_count"]["value"] / scalars["physical_cores"] * 100
973
+ }
974
+ if (
975
+ scalars.get("task_duration_us")
976
+ and facts.get("time_max_us", {}).get("value") is not None
977
+ ):
978
+ # 木桶口径:头开销以最慢核为基准(Task 总时长 − 最慢核主体时间)
979
+ td, tmax = scalars["task_duration_us"], facts["time_max_us"]["value"]
980
+ if td > 0:
981
+ facts["__head_overhead_pct"] = {"value": (td - tmax) / td * 100}
982
+ # L2 derived:host 下发占比(scene=cluster 档;host_dispatch_us
983
+ # 暂无生产者——真实集群数据到位前本规则维持 SKIPPED,绑定契约兜底)
984
+ if scalars.get("host_dispatch_us") and scalars.get("task_duration_us"):
985
+ td2 = scalars["task_duration_us"]
986
+ if td2 > 0:
987
+ facts["__host_dispatch_pct"] = {
988
+ "value": scalars["host_dispatch_us"] / td2 * 100
989
+ }
990
+
991
+ rules = sorted(pack.get("rules", []), key=lambda r: r.get("priority", 999))
992
+ for rule in rules:
993
+ rule["_metrics_spec"] = metrics_spec
994
+ rule["_layer"] = pack.get("layer", "")
995
+ res = eval_rule(rule, facts, metrics_spec, scalars, disabled)
996
+ if res.get("status") == "HIT":
997
+ all_findings.append(res)
998
+ # 路由副作用生效:禁用后续规则(跨包也生效,如 L3 污染禁用 L1_MTE2_BOUND)
999
+ for act in (res.get("routing", {}) or {}).get("on_hit", []):
1000
+ if isinstance(act, dict) and act.get("disable_rule"):
1001
+ disabled.add(act["disable_rule"])
1002
+ elif isinstance(act, str):
1003
+ disabled.add(act)
1004
+ elif res.get("status") in ("SKIPPED", "INSUFFICIENT_DATA"):
1005
+ all_skipped.append(res)
1006
+ elif res.get("status") == "NOT_HIT":
1007
+ all_skipped.append(res)
1008
+
1009
+ headline, verdict, next_steps = headline_and_verdict(
1010
+ all_findings, all_skipped, rule_seeds=all_rule_seeds
1011
+ )
1012
+
1013
+ # 事实快照(审计:判定书可回溯到指标值与来源)——按规则包分层输出:
1014
+ # 全瀑布 --rules L3,L2,L1,L0 时保留每包的完整指标事实(含 L1 pipe 指标),
1015
+ # 不再只剩最后一个包的 facts;scalars 字段维持现状(不依赖包)
1016
+ def _snap(f: dict) -> dict:
1017
+ return {
1018
+ k: {
1019
+ kk: (round(vv, 2) if isinstance(vv, float) else vv)
1020
+ for kk, vv in v.items()
1021
+ }
1022
+ for k, v in f.items()
1023
+ }
1024
+
1025
+ facts_snapshot = (
1026
+ {pack_stem: _snap(f) for pack_stem, f in facts_by_pack.items()}
1027
+ if (rows or any(v is not None and v for v in scalars.values()))
1028
+ else {}
1029
+ )
1030
+
1031
+ # watch 观察档(R2 风险对策的「watch 档灰度输出」要求可见,
1032
+ # 此前只在 verdict.json 内部、终端与 recommended_next 均不呈现)
1033
+ watches = [
1034
+ (s["rule_id"], s["watch"])
1035
+ for s in all_skipped
1036
+ if s.get("status") == "NOT_HIT" and s.get("watch")
1037
+ ]
1038
+ if watches:
1039
+ # watch 档进 recommended_next(判定书与终端同源)
1040
+ next_steps.append(
1041
+ f"watch 档灰度输出:{', '.join(rid for rid, _ in watches)}"
1042
+ f"(指标已具备优化价值但未达判定线,可低成本先行)"
1043
+ )
1044
+
1045
+ out = {
1046
+ "schema": SCHEMA_VERDICT,
1047
+ "generated_at": datetime.datetime.now().isoformat(timespec="seconds"),
1048
+ "soc": soc,
1049
+ "rules_files": rules_files,
1050
+ "csv": args.csv,
1051
+ "db": args.db,
1052
+ "db_table": args.db_table if args.db else None,
1053
+ "kernel_name": args.kernel_name,
1054
+ "rows": len(rows),
1055
+ "kernels_in_csv": sorted(k for k in kernel_groups if k != "<all>")
1056
+ if len(kernel_groups) > 1
1057
+ else None,
1058
+ "scalars": {k: v for k, v in scalars.items()},
1059
+ "facts": facts_snapshot,
1060
+ "findings": all_findings,
1061
+ "skipped": all_skipped,
1062
+ "verdict": verdict,
1063
+ "headline": headline,
1064
+ "recommended_next": next_steps,
1065
+ }
1066
+ out_path = Path(args.output)
1067
+ out_path.parent.mkdir(parents=True, exist_ok=True)
1068
+ out_path.write_text(
1069
+ json.dumps(out, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
1070
+ )
1071
+
1072
+ # 人读摘要(Agent/终端共用)
1073
+ print(f"verdict: {verdict} | {headline}")
1074
+ for f in all_findings:
1075
+ if f.get("status") == "HIT":
1076
+ print(
1077
+ f" HIT [{f['severity']:>8}/{f['confidence']:<6}] {f['rule_id']}: {f['name']} "
1078
+ f"(est {f.get('speedup_range')}) evidence: {f['evidence']}"
1079
+ )
1080
+ for ce in f.get("counter_evidence", []):
1081
+ print(f" ⚠ 反证[{ce['id']}]: {ce['note']}")
1082
+ if watches:
1083
+ print(f" watch 档(未达判定线,观察项 {len(watches)}):")
1084
+ for rid, note in watches:
1085
+ print(f" 👁 watch [{rid}]: {note}")
1086
+ n_skip = len([s for s in all_skipped if s.get("status") == "SKIPPED"])
1087
+ n_ins = len([s for s in all_skipped if s.get("status") == "INSUFFICIENT_DATA"])
1088
+ print(f" skipped={n_skip} insufficient_data={n_ins}")
1089
+ print(f" → {out_path}")
1090
+ return 0
1091
+
1092
+
1093
+ if __name__ == "__main__":
1094
+ sys.exit(main())