@furongjun1999/dsh-memory 0.4.7 → 0.4.9

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 (325) hide show
  1. package/README.md +130 -47
  2. package/codebuddy/CODEBUDDY.md +21 -10
  3. package/codebuddy/README.md +13 -1
  4. package/codebuddy/mcp.json +9 -0
  5. package/docs/GBrain/345/217/257/345/200/237/351/211/264/347/202/271_/347/201/265/346/236/242/350/220/275/347/202/271/344/272/244/346/216/245_20260919.md +169 -0
  6. package/docs/Pi/345/217/257/345/255/246/344/271/240/344/274/230/347/202/271_/347/201/265/346/236/242/345/244/247/350/204/221/346/224/271/350/277/233/344/272/244/346/216/245_20260915.md +144 -0
  7. package/docs/README.md +111 -0
  8. package/docs/discipline/harnesses.yaml +226 -152
  9. package/docs/discipline/templates/full.md.tmpl +61 -58
  10. package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_LoCoMo_/347/201/265/346/236/242_.md +127 -0
  11. package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_LoCoMo_/347/201/265/346/236/242_.png +0 -0
  12. package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_/347/201/265/346/236/242_vs_dejavu_/347/273/237/344/270/200/350/257/204/345/210/206_v7.md +202 -0
  13. package/docs/experiments/linkref_backfill/candidates_20260917.json +726 -0
  14. package/docs/experiments/linkref_backfill/candidates_internal_20260917.json +602 -0
  15. package/docs/experiments/linkref_backfill/candidates_internal_v2.json +603 -0
  16. package/docs/experiments/linkref_backfill/candidates_secret_20260917.json +884 -0
  17. package/docs/experiments/linkref_backfill/candidates_secret_v2.json +789 -0
  18. package/docs/experiments/m4-role-probe/census.py +86 -0
  19. package/docs/experiments/m4-role-probe/probe.py +89 -0
  20. package/docs/experiments/mapped_confidence/bench_mapped_conf.py +216 -0
  21. package/docs/experiments/mapped_confidence/post_check.py +75 -0
  22. package/docs/experiments/mapped_confidence/repro_thirdparty_tol.py +83 -0
  23. package/docs/experiments/mapped_confidence/result_mapped_conf.json +215 -0
  24. package/docs/hive//345/244/232/347/253/257harness/351/200/232/344/277/241/345/245/221/347/272/246_v0.1.md +42 -0
  25. package/docs/hive//346/243/200/347/264/242/346/224/266/346/225/233/345/256/236/346/265/213/344/270/216S1b/350/256/276/350/256/241_v0.1.md +43 -0
  26. package/docs/hive//346/243/200/347/264/242/350/267/257/345/276/204/344/270/216/350/256/244/347/237/245/347/273/223/346/236/204/345/245/221/347/272/246_v0.1.md +102 -0
  27. package/docs/hive//347/234/237/345/256/236/345/272/223/347/253/257/345/210/260/347/253/257/345/256/236/346/265/213_S1b/344/270/216/345/217/254/345/233/236/346/235/203/350/241/241_v0.1.md +57 -0
  28. package/docs/hive//347/234/237/345/256/236/345/272/223/347/253/257/345/210/260/347/253/257/345/256/236/346/265/213_S7/345/200/222/346/216/222/345/200/231/351/200/211/345/261/202_v0.1.md +126 -0
  29. package/docs/hive//350/234/202/345/267/242/345/217/214/345/256/236/344/276/213/344/272/222/351/252/214_/350/256/276/350/256/241/345/256/232/347/250/277.md +503 -0
  30. package/docs/{ → hive/}/350/234/202/345/267/242/345/267/245/344/275/234/350/256/260/345/277/206_/351/241/271/347/233/256/350/256/241/345/210/222.md +14 -2
  31. package/docs/mdcg/D_meta_/345/267/245/347/250/213/345/214/226/346/226/271/346/241/210_v0.2.md +216 -0
  32. package/docs/{README → mdcg/README}/350/257/246/347/273/206/347/211/210_v0.4.5.md +631 -625
  33. package/docs/{ → mdcg/}/344/270/273/344/273/243/347/220/206/345/255/220/344/273/243/347/220/206/350/256/260/345/277/206/346/236/266/346/236/204/350/256/276/350/256/241.md +1 -1
  34. package/docs/mdcg//344/273/243/347/240/201/350/257/204/345/256/241/344/270/216/346/235/241/344/273/266/345/214/226/346/263/250/351/207/212_/345/245/221/347/272/246_v0.1.md +82 -0
  35. package/docs/mdcg//345/205/250/345/272/223/344/273/243/347/240/201/350/257/204/345/256/241/344/270/216/346/235/241/344/273/266/345/214/226/346/263/250/351/207/212_/350/256/241/345/210/222_v0.1.md +600 -0
  36. package/docs/mdcg//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +263 -0
  37. package/docs/{ → mdcg/}/345/215/225/345/205/203/350/207/252/346/210/221/351/224/232/347/202/271_/347/263/273/347/273/237/346/217/220/347/244/272/350/257/215/346/240/207/345/207/206_v0.3.md +1 -1
  38. package/docs/mdcg//345/255/220/344/273/243/347/220/206/351/205/215/347/275/256/346/240/207/345/207/206_v0.5.md +236 -0
  39. package/docs/{ → mdcg/}/346/272/220/347/240/201/347/272/247/346/236/266/346/236/204/345/256/241/350/256/241_GPT/346/211/271/350/257/204/345/257/271/347/205/247_v1.0.md +2 -2
  40. package/docs/{ → mdcg/}/347/201/265/346/236/242/344/270/211/345/261/202/346/213/206/345/210/206/350/247/204/345/210/222_v0.1.md +181 -181
  41. package/docs/mdcg//347/201/265/346/236/242/350/256/260/345/277/206/345/212/250/350/257/215/345/215/217/350/256/256_v1.0-draft.md +172 -0
  42. package/docs/mdcg//347/216/257/344/272/214_/347/231/275/347/256/261/345/241/253/345/205/205/346/265/201/346/260/264/347/272/277_v0.1.md +31 -0
  43. package/docs/{ → mdcg/}/347/274/272/345/217/243/345/215/225_P0/346/224/266/345/217/243_v0.1.md +2 -2
  44. package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_G4-G8/347/274/272/345/217/243/350/243/201/345/256/232/345/215/225_v0.1.md +1 -1
  45. package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_/347/264/242/345/274/225/344/270/216/345/267/245/347/250/213/350/247/204/350/214/203/345/214/226_/350/256/241/345/210/222_v0.1.md +4 -4
  46. package/docs/{ → mdcg/}/350/256/260/345/277/206/346/223/215/344/275/234/347/263/273/347/273/237_MdCGOS/344/270/216MCP/346/216/245/345/205/245_v0.1.md +2 -2
  47. package/docs/mdcg//350/267/250/347/253/257/351/252/214/350/257/201/344/270/216/345/220/214/346/255/245/345/215/217/350/256/256_v0.1.md +93 -0
  48. package/docs/plans/GridWorld/346/234/200/345/260/217/351/227/255/347/216/257/350/247/204/346/240/274_v0.1.md +176 -0
  49. package/docs/{ → swarm/}/350/234/202/347/276/244/344/272/222/350/201/224_v0.1.md +3 -3
  50. package/docs/swarm//350/234/202/347/276/244/345/220/214/351/224/231/346/243/200/346/265/213/345/256/236/351/252/214/345/215/217/350/256/256_v0.1.md +242 -0
  51. package/docs/theory//345/215/225/347/272/277/347/250/213/344/270/216/346/263/250/346/204/217/345/212/233/351/233/206/344/270/255_/346/227/240/344/272/211/350/256/256/347/220/206/350/256/272/346/226/207/346/241/243_v1.0.md +129 -0
  52. package/docs/theory//345/271/266/345/217/221/345/277/205/347/204/266/346/200/247/347/220/206/350/256/272_v0.2.md +134 -0
  53. package/docs/theory//346/246/202/345/277/265/345/210/206/345/261/202/345/257/271/351/275/220/350/241/250_v0.1.md +145 -0
  54. package/docs/{ → theory/}/347/220/206/350/256/272_/346/234/272/345/210/266_/344/273/243/347/240/201_/345/256/236/351/252/214_/347/274/272/345/217/243/347/237/251/351/230/265_v0.1.md +6 -6
  55. package/docs/{ → theory/}/347/220/206/350/256/272/344/273/223/346/213/206/345/210/206/344/270/216/347/231/275/347/256/261/347/237/245/350/257/206/345/272/223/345/206/205/350/277/201_v0.1.md +1 -1
  56. package/docs/theory//350/256/244/347/237/245/344/273/243/347/220/206/344/270/216/346/224/266/346/225/233/347/273/223/346/236/204_/346/235/241/344/273/266/350/256/272/351/207/215/346/236/204_v0.1.md +221 -0
  57. package/docs/world_model//344/270/226/347/225/214/346/250/241/345/236/213_/347/245/236/347/273/217/347/275/221/347/273/234/345/272/225/345/261/202/346/236/266/346/236/204_v1.0.md +237 -0
  58. package/docs//345/255/230/347/256/227/344/270/200/344/275/223/346/236/266/346/236/204/345/255/246/344/271/240_/345/244/226/351/203/250/347/220/206/350/256/272/345/257/271/347/205/247/344/270/216/350/267/257/347/272/277/344/272/244/346/216/245_20260916.md +98 -0
  59. package/docs//345/255/230/347/256/227/344/270/200/344/275/223/347/245/236/347/273/217/347/275/221/347/273/234/346/236/266/346/236/204_/346/200/273/347/272/262/344/270/216/344/272/244/346/216/245_20260916.md +109 -0
  60. package/docs//345/267/245/344/275/234/347/272/252/345/276/213_/350/256/244/347/237/245/345/233/276/346/235/241/347/233/256_v1.1.json +434 -405
  61. package/docs//347/201/265/346/236/242/350/207/252/346/210/221/346/224/271/350/277/233/345/267/245/344/275/234/350/256/241/345/210/222_/345/244/226/351/203/250/347/240/224/347/251/266/347/263/273/345/210/227/345/220/270/346/224/266_v1_20260919.md +286 -0
  62. package/docs//347/231/275/347/256/261/345/214/226/347/272/262/351/242/206_/344/270/211/351/241/271/347/233/256/345/255/246/344/271/240/346/200/273/346/236/266/346/236/204/344/270/216Ghidra/344/272/244/346/216/245_20260916.md +104 -0
  63. package/docs//350/256/260/345/277/206/350/257/204/345/256/241/347/263/273/347/273/237_/347/253/213/351/241/271/350/256/276/350/256/241/344/270/216/346/226/275/345/267/245/344/272/244/346/216/245_20260915.md +183 -0
  64. package/dsh/README.md +34 -1
  65. package/dsh/cordis.yml.example +13 -7
  66. package/dsh/hive-mcp-probe.mjs +94 -0
  67. package/dsh/hive-mcp.example.yml +62 -0
  68. package/dsh/update-lingshu.bat +11 -0
  69. package/dsh/update-lingshu.ps1 +337 -0
  70. package/lib/hooks.d.ts +8 -0
  71. package/lib/hooks.js +27 -24
  72. package/lib/index.d.ts +4 -2
  73. package/lib/index.js +29 -6
  74. package/lib/lib/datapath.d.ts +76 -1
  75. package/lib/lib/datapath.js +199 -13
  76. package/lib/lib/mdcg_client.d.ts +6 -3
  77. package/lib/lib/mdcg_client.js +6 -5
  78. package/lib/lib/mutual.js +4 -4
  79. package/lib/lib/prompt_safety.d.ts +48 -0
  80. package/lib/lib/prompt_safety.js +62 -0
  81. package/lib/lib/token_store.js +4 -5
  82. package/md_cg/audit.py +91 -2
  83. package/md_cg/autonomy.py +86 -15
  84. package/md_cg/backfill.py +36 -1
  85. package/md_cg/backfill_bigdomain.py +34 -0
  86. package/md_cg/bench6_arms.py +28 -1
  87. package/md_cg/bench6_common.py +10 -1
  88. package/md_cg/bench6_competitors.py +6 -1
  89. package/md_cg/bench_axis_domain.py +9 -1
  90. package/md_cg/bench_blind_comp.py +7 -1
  91. package/md_cg/bench_en_atoms_public.py +9 -0
  92. package/md_cg/bench_governance.py +348 -0
  93. package/md_cg/bench_lme_zh.py +16 -1
  94. package/md_cg/bench_locomo.py +2 -1
  95. package/md_cg/bench_locomo_zh.py +16 -1
  96. package/md_cg/bench_locomo_zh_public.py +4 -1
  97. package/md_cg/bench_longmem.py +2 -1
  98. package/md_cg/bench_membench.py +37 -6
  99. package/md_cg/bench_p0.py +4 -1
  100. package/md_cg/bench_progressive.py +61 -10
  101. package/md_cg/bench_role_views.py +238 -0
  102. package/md_cg/bench_task_ab.py +8 -1
  103. package/md_cg/bench_task_ab_llm.py +13 -1
  104. package/md_cg/bench_unified_en.py +6 -1
  105. package/md_cg/bench_zh_mad.py +20 -1
  106. package/md_cg/blindspot_tickets.py +123 -0
  107. package/md_cg/branches.py +286 -0
  108. package/md_cg/build_postings.py +73 -0
  109. package/md_cg/ccgc.py +949 -0
  110. package/md_cg/census.py +5 -1
  111. package/md_cg/chain.py +24 -3
  112. package/md_cg/codeindex.py +134 -17
  113. package/md_cg/coldverify.py +265 -0
  114. package/md_cg/comment_gate.py +338 -0
  115. package/md_cg/cond_compose.py +190 -0
  116. package/md_cg/cond_facts.py +155 -0
  117. package/md_cg/cond_template.json +107 -0
  118. package/md_cg/condition_anchor.py +143 -0
  119. package/md_cg/conformance.py +727 -0
  120. package/md_cg/consistency.py +25 -2
  121. package/md_cg/consolidate.py +53 -2
  122. package/md_cg/corpus.py +5 -1
  123. package/md_cg/crosscheck.py +42 -2
  124. package/md_cg/crypto.py +35 -1
  125. package/md_cg/d_meta.py +310 -0
  126. package/md_cg/datapath.py +201 -26
  127. package/md_cg/docindex.py +122 -1
  128. package/md_cg/eval_common.py +35 -6
  129. package/md_cg/evidence.py +27 -1
  130. package/md_cg/evolution.py +21 -1
  131. package/md_cg/export.py +11 -1
  132. package/md_cg/forgetting.py +34 -4
  133. package/md_cg/fsutil.py +81 -2
  134. package/md_cg/hotcache.py +214 -0
  135. package/md_cg/hyperedge.py +251 -0
  136. package/md_cg/identity.py +20 -3
  137. package/md_cg/insight.py +19 -3
  138. package/md_cg/lexicon/build_cedict_en_zh.py +9 -0
  139. package/md_cg/lexicon/build_standard_en.py +171 -168
  140. package/md_cg/lexicon/expand_en_zh.py +6 -0
  141. package/md_cg/lifecycle.py +273 -0
  142. package/md_cg/linkref.py +281 -0
  143. package/md_cg/links.py +29 -1
  144. package/md_cg/mcp_server.py +894 -168
  145. package/md_cg/md_whitebox.py +53 -1
  146. package/md_cg/mdcg.py +1205 -41
  147. package/md_cg/mdcos.py +1060 -76
  148. package/md_cg/metacognition.py +39 -4
  149. package/md_cg/migrate.py +4 -0
  150. package/md_cg/migrate_aeis.py +221 -213
  151. package/md_cg/migrate_roleplay.py +8 -0
  152. package/md_cg/migrate_wisdom_graph.py +14 -1
  153. package/md_cg/mreview/__init__.py +25 -0
  154. package/md_cg/mreview/__main__.py +110 -0
  155. package/md_cg/mreview/bundle.py +178 -0
  156. package/md_cg/mreview/candidates.py +262 -0
  157. package/md_cg/mreview/govern.py +694 -0
  158. package/md_cg/mreview/locate.py +939 -0
  159. package/md_cg/mreview/pipeline.py +729 -0
  160. package/md_cg/mreview/rules/duplication.json +21 -0
  161. package/md_cg/mreview/rules/field_coverage.json +54 -0
  162. package/md_cg/mreview/rules/source_license.json +21 -0
  163. package/md_cg/mreview/rules/template_flow.json +21 -0
  164. package/md_cg/mreview/ruleset.py +253 -0
  165. package/md_cg/nodefile.py +269 -1
  166. package/md_cg/pooling.py +23 -1
  167. package/md_cg/postings.py +298 -0
  168. package/md_cg/predict.py +113 -15
  169. package/md_cg/progressive.py +3 -0
  170. package/md_cg/protect.py +18 -5
  171. package/md_cg/protocol.py +372 -0
  172. package/md_cg/provenance.py +262 -0
  173. package/md_cg/reach.py +453 -0
  174. package/md_cg/refindex.py +88 -4
  175. package/md_cg/refine.py +20 -1
  176. package/md_cg/roleviews.py +89 -0
  177. package/md_cg/routing.py +76 -0
  178. package/md_cg/scrub.py +68 -3
  179. package/md_cg/security.py +26 -1
  180. package/md_cg/self_state.py +65 -2
  181. package/md_cg/selfreport.py +151 -0
  182. package/md_cg/semantic/canonical.py +5 -0
  183. package/md_cg/semantic/en_normalizer.py +364 -295
  184. package/md_cg/semantic/zh_en_atoms.py +139 -136
  185. package/md_cg/signer.py +41 -1
  186. package/md_cg/sources.py +583 -547
  187. package/md_cg/statushdr.py +179 -0
  188. package/md_cg/stg.py +59 -18
  189. package/md_cg/subgraph.py +23 -0
  190. package/md_cg/sustain.py +74 -1
  191. package/md_cg/tasks.py +471 -0
  192. package/md_cg/test_action_derive.py +203 -0
  193. package/md_cg/test_audit_rotate.py +270 -0
  194. package/md_cg/test_autonomy.py +26 -0
  195. package/md_cg/test_bench_governance.py +102 -0
  196. package/md_cg/test_blindspot_tickets.py +166 -0
  197. package/md_cg/test_branches.py +249 -0
  198. package/md_cg/test_ccg_perturb.py +1 -1
  199. package/md_cg/test_ccgc.py +433 -0
  200. package/md_cg/test_codeindex.py +338 -0
  201. package/md_cg/test_comment_gate.py +187 -0
  202. package/md_cg/test_cond_compose_anchors.py +76 -0
  203. package/md_cg/test_condition_anchor.py +82 -0
  204. package/md_cg/test_conformance.py +343 -0
  205. package/md_cg/test_d_meta.py +412 -0
  206. package/md_cg/test_datapath_root.py +188 -0
  207. package/md_cg/test_en_pipeline.py +24 -0
  208. package/md_cg/test_gain_gate.py +47 -1
  209. package/md_cg/test_health_scale.py +173 -0
  210. package/md_cg/test_hot_cold.py +187 -0
  211. package/md_cg/test_hyperedge.py +245 -0
  212. package/md_cg/test_identity_attribution.py +6 -0
  213. package/md_cg/test_index_durability.py +224 -0
  214. package/md_cg/test_lifecycle.py +309 -0
  215. package/md_cg/test_linkref.py +306 -0
  216. package/md_cg/test_md_access_parity.py +15 -3
  217. package/md_cg/test_mr_m1.py +769 -0
  218. package/md_cg/test_mr_m2.py +587 -0
  219. package/md_cg/test_mr_m3.py +710 -0
  220. package/md_cg/test_mr_m4.py +485 -0
  221. package/md_cg/test_p1.py +1 -1
  222. package/md_cg/test_p11_consistency.py +1 -1
  223. package/md_cg/test_p12_metacognition.py +2 -2
  224. package/md_cg/test_p16_self_state.py +1 -1
  225. package/md_cg/test_p26_refindex.py +50 -21
  226. package/md_cg/test_p27_docindex.py +258 -4
  227. package/md_cg/test_p28_refcheck.py +1 -1
  228. package/md_cg/test_p29_session_ingest_export.py +1 -1
  229. package/md_cg/test_p2_mcp.py +7 -1
  230. package/md_cg/test_p31_insight.py +24 -0
  231. package/md_cg/test_p38_contextualize.py +1 -1
  232. package/md_cg/test_p39_vision_evidence.py +1 -1
  233. package/md_cg/test_p40_refine_worklist.py +1 -1
  234. package/md_cg/test_p41_evolve_patrol.py +1 -1
  235. package/md_cg/test_p42_provenance.py +1 -1
  236. package/md_cg/test_p43_pooling.py +41 -13
  237. package/md_cg/test_p44_md_whitebox.py +14 -1
  238. package/md_cg/test_protocol.py +243 -0
  239. package/md_cg/test_reach.py +378 -0
  240. package/md_cg/test_reach_keys.py +201 -0
  241. package/md_cg/test_reach_meta_exits.py +145 -0
  242. package/md_cg/test_read_clip.py +141 -0
  243. package/md_cg/test_retr_s1.py +340 -0
  244. package/md_cg/test_retr_s1b.py +209 -0
  245. package/md_cg/test_retr_s3.py +194 -0
  246. package/md_cg/test_retr_s4.py +163 -0
  247. package/md_cg/test_retr_s5.py +200 -0
  248. package/md_cg/test_retr_s6.py +157 -0
  249. package/md_cg/test_retr_s7.py +385 -0
  250. package/md_cg/test_retr_s8_time.py +316 -0
  251. package/md_cg/test_retr_s9_edges.py +286 -0
  252. package/md_cg/test_retr_s9_entity_ctx.py +175 -0
  253. package/md_cg/test_review_conformance.py +367 -0
  254. package/md_cg/test_role_views.py +354 -0
  255. package/md_cg/test_tasks.py +409 -0
  256. package/md_cg/test_tool_face.py +189 -0
  257. package/md_cg/test_trust.py +361 -0
  258. package/md_cg/test_twophase.py +286 -0
  259. package/md_cg/test_units_poll.py +71 -0
  260. package/md_cg/test_v14_fixes.py +397 -0
  261. package/md_cg/test_validity_filter.py +280 -0
  262. package/md_cg/test_wisdom_md_store.py +7 -3
  263. package/md_cg/test_writepipe.py +214 -0
  264. package/md_cg/theory.py +17 -2
  265. package/md_cg/tokens.py +134 -12
  266. package/md_cg/tool_face.py +261 -0
  267. package/md_cg/trust.py +943 -0
  268. package/md_cg/twophase.py +232 -0
  269. package/md_cg/units.py +665 -0
  270. package/md_cg/vision_evidence.py +25 -2
  271. package/md_cg/weights.py +25 -2
  272. package/md_cg/whitebox.py +33 -2
  273. package/md_cg/whitebox_kb/data/verify_cache.json +21233 -360
  274. package/md_cg/whitebox_kb/data/verify_savings.jsonl +5124 -0
  275. package/md_cg/whitebox_kb/wisdom/audit_log/chain_heat.json +10 -10
  276. package/md_cg/whitebox_kb/wisdom/code_compose.py +113 -6
  277. package/md_cg/whitebox_kb/wisdom/code_solidified.json +1 -1
  278. package/md_cg/whitebox_kb/wisdom/verifier.py +340 -55
  279. package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db +0 -0
  280. package/md_cg/writelimit.py +37 -7
  281. package/md_cg/writepipe.py +543 -0
  282. package/package.json +2 -2
  283. package/skills/skills/designer-perspective/scripts/__pycache__/designer.cpython-310.pyc +0 -0
  284. package/skills/skills/designer-perspective/scripts/designer.py +17 -1
  285. package/skills/skills/designer-perspective/tests/selftest.py +3 -1
  286. package/src/hooks.ts +27 -22
  287. package/src/index.ts +33 -6
  288. package/src/lib/datapath.ts +211 -13
  289. package/src/lib/mdcg_client.ts +12 -8
  290. package/src/lib/mutual.ts +411 -411
  291. package/src/lib/prompt_safety.ts +62 -0
  292. package/src/lib/token_store.ts +4 -5
  293. package/zcode/AGENTS.md +21 -10
  294. package/zcode/README.md +4 -0
  295. package/docs//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +0 -221
  296. /package/docs/{AGI → eval/AGI}/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v1.0.md" +0 -0
  297. /package/docs/{AGI → eval/AGI}/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v2.0.md" +0 -0
  298. /package/docs/{ → eval/}/345/256/236/351/252/214/346/226/271/346/241/210_/345/255/246/344/271/240/351/227/255/347/216/257AB/344/270/216/346/250/252/350/257/204_v1.0.md" +0 -0
  299. /package/docs/{ → eval/}/346/250/252/350/257/204_/345/205/255/345/256/266100/351/242/230/344/270/255/350/213/261/345/217/214/346/237/245_v1.0.md" +0 -0
  300. /package/docs/{guardrail-charter.md → mdcg/guardrail-charter.md} +0 -0
  301. /package/docs/{lingshu_tutorial.html → mdcg/lingshu_tutorial.html} +0 -0
  302. /package/docs/{memory-assessment.html → mdcg/memory-assessment.html} +0 -0
  303. /package/docs/{memory_score.html → mdcg/memory_score.html} +0 -0
  304. /package/docs/{memory_score.png → mdcg/memory_score.png} +0 -0
  305. /package/docs/{release_v0.3.0.md → mdcg/release_v0.3.0.md} +0 -0
  306. /package/docs/{release_v0.4.5.md → mdcg/release_v0.4.5.md} +0 -0
  307. /package/docs/{tool_table_v0.3.0.md → mdcg/tool_table_v0.3.0.md} +0 -0
  308. /package/docs/{ → mdcg/}/344/273/244/347/211/214/344/270/216/350/247/222/350/211/262/346/235/203/350/201/214/345/210/206/347/246/273_v0.1.md" +0 -0
  309. /package/docs/{ → mdcg/}/347/201/265/346/236/24282/345/267/245/345/205/267_/345/212/237/350/203/275/346/225/264/347/220/206/344/270/216/350/277/201/347/247/273/346/230/240/345/260/204_v0.1.md" +0 -0
  310. /package/docs/{ → mdcg/}/347/201/265/346/236/242MCP/345/267/245/345/205/267/346/200/273/350/241/250_v3.4.md" +0 -0
  311. /package/docs/{ → mdcg/}/347/201/265/346/236/242_/350/207/252/346/210/221/345/261/202/345/256/232/344/271/211.md" +0 -0
  312. /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_MD/347/233/256/345/275/225/346/226/271/346/241/210_v0.1.md" +0 -0
  313. /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_/346/235/241/344/273/266/347/251/272/351/227/264/345/220/210/346/210/220/344/270/216/347/224/237/346/225/210/346/235/241/344/273/266/345/217/243/345/276/204_v0.1.md" +0 -0
  314. /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276/344/275/234/344/270/272/350/256/260/345/277/206/346/223/215/344/275/234/347/263/273/347/273/237_/350/257/204/344/274/260/344/270/216/350/267/257/347/272/277_v0.1.md" +0 -0
  315. /package/docs/{ → plans/}/345/221/275/345/220/215/346/262/273/347/220/206_/351/241/271/347/233/256/350/256/241/345/210/222.md" +0 -0
  316. /package/docs/{ → plans/}/347/237/245/350/257/206/345/233/276/350/260/261/351/241/271/347/233/256_/344/272/244/346/216/245/346/226/207/346/241/243_20260914.md" +0 -0
  317. /package/docs/{ → swarm/}/350/234/202/347/276/244/345/244/232/346/231/272/350/203/275/344/275/223_/344/275/277/347/224/250/346/212/245/345/221/212_20260913.md" +0 -0
  318. /package/docs/{ → swarm/}/350/234/202/347/276/244/345/244/232/346/231/272/350/203/275/344/275/223_/345/212/237/350/203/275/350/257/264/346/230/216_v0.6.md" +0 -0
  319. /package/docs/{ → swarm/}/350/234/202/347/276/244/347/233/262/345/214/272/346/240/207/350/256/260_v1.0.md" +0 -0
  320. /package/docs/{ → theory/}/344/277/241/346/201/257/345/267/256/344/270/272/344/273/200/344/271/210/345/277/205/347/204/266/345/255/230/345/234/250/344/270/224/350/207/252/347/204/266/346/211/251/345/244/247.md" +0 -0
  321. /package/docs/{ → theory/}/346/231/272/350/203/275/347/232/204/345/205/254/347/220/206/345/214/226/345/237/272/347/237/263.md" +0 -0
  322. /package/docs/{ → theory/}/346/231/272/350/203/275/347/232/204/350/256/244/347/237/245/350/277/207/347/250/213.md" +0 -0
  323. /package/docs/{ → theory/}/346/231/272/350/203/275/350/256/2723.4.md" +0 -0
  324. /package/docs/{ → theory/}/347/231/275/347/256/261/346/231/272/350/203/275/346/230/257/344/273/200/344/271/210/357/274/237.md" +0 -0
  325. /package/docs/{ → theory/}/347/231/275/347/256/261/346/231/272/350/203/275/347/263/273/345/210/227/302/267/347/254/254/344/272/224/347/257/207/357/274/232/350/256/251AI/347/234/237/346/255/243/350/243/205/344/270/212/350/256/260/345/277/206.md" +0 -0
package/md_cg/census.py CHANGED
@@ -31,6 +31,7 @@ DEFAULT_ROOT = os.path.join(
31
31
  ARCHIVE_DIRS = ("trash", "_protected_history", "_protected", "_index_log", "hippocampus")
32
32
 
33
33
 
34
+ # 生效条件:当 root 为记忆库根目录、其下 .md 能被 nodefile.loads 解析出 frontmatter 时,返回 [(node_id, layer, condition_space, tags)...];ARCHIVE_DIRS 与 _protected_history_ 目录整棵剪枝,无 frontmatter 的 md 跳过。
34
35
  def load(root):
35
36
  """遍历 md 记忆库根,返回 [(node_id, layer, condition_space, tags), ...]。
36
37
 
@@ -62,6 +63,7 @@ def load(root):
62
63
  return out
63
64
 
64
65
 
66
+ # 生效条件:rows 非空、每行可解包为 (_, _, d, t) 且 keyfn(d, t) 可调用时,打印桶数、最大桶占比、单例桶比与期望扫描占比,无返回值。
65
67
  def report(name, rows, keyfn):
66
68
  cnt = collections.Counter(keyfn(d, t) for _, _, d, t in rows)
67
69
  n = len(rows)
@@ -78,12 +80,14 @@ def report(name, rows, keyfn):
78
80
  print(f" ★条件路由后期望扫描占比 = {exp * 100:.1f}% (100%=退化成全量, 越低越有效)")
79
81
 
80
82
 
83
+ # 生效条件:传入 keys(任意可迭代键序列,含空序列时对 json.dumps({}) 求哈希)即返回一个接收 (d, t) 的 lambda,该 lambda 按 keys 逐个取 d.get(k)(缺键得 None)并 sort_keys=True、ensure_ascii=False 序列化后取 sha256 十六进制前 10 位,形参 t 不参与计算。
81
84
  def by_keys(keys):
82
85
  return lambda d, t: hashlib.sha256(
83
86
  json.dumps({k: d.get(k) for k in keys}, sort_keys=True,
84
87
  ensure_ascii=False).encode()).hexdigest()[:10]
85
88
 
86
89
 
90
+ # 生效条件:以 root 调用 load(root) 得 rows,先打印「总节点: len(rows)」(空序列也会先打印该行),仅当 rows 为假值时才打印空库提示并 return 2,否则继续打印分层与各维度取值分布、并执行方案A/B/C/D 的 report 后 return 0。
87
91
  def main(root):
88
92
  rows = load(root)
89
93
  print(f"md 记忆库: {root}")
@@ -126,4 +130,4 @@ if __name__ == "__main__":
126
130
  # 会在解释器退出阶段丢缓冲(实测只落盘 444 字节),CI 里会看不到失败原因。
127
131
  if hasattr(sys.stdout, "reconfigure"):
128
132
  sys.stdout.reconfigure(encoding="utf-8")
129
- sys.exit(main(sys.argv[1] if len(sys.argv) > 1 else DEFAULT_ROOT))
133
+ sys.exit(main(sys.argv[1] if len(sys.argv) > 1 else DEFAULT_ROOT))
package/md_cg/chain.py CHANGED
@@ -39,11 +39,17 @@ EDGE_WEIGHTS = {
39
39
  "correlational": 0.45,
40
40
  "cyclic": 0.35,
41
41
  "opposite": 0.30,
42
+ # 正文引用边(linkref,写入侧自动解析,2026-09-17):取弱权重——正文提及
43
+ # ≠ 语义相似 ≠ 因果依赖,故与 DEFAULT_EDGE_WEIGHT 同值;显式登记的意义在
44
+ # 「类型已知」(可审计、可按类型调参、可区分于未登记类型的兜底默认)。
45
+ "reference": 0.50,
42
46
  }
43
47
  DEFAULT_EDGE_WEIGHT = 0.50
44
48
 
45
49
  CAUSAL_TYPES = ("causal",)
46
50
  # 检索默认沿「有语义方向」的关系走:因果 / 时序 / 条件适用
51
+ # 注:reference **刻意不入**——正文提及不应进入「前提→结论」条件序列遍历,
52
+ # 否则 causal 链会被「提到过」这类无向弱关联稀释(模式分离)。
47
53
  CHAIN_TYPES_DEFAULT = ("causal", "sequential", "applies_to")
48
54
 
49
55
  MAX_DEPTH_DEFAULT = 5
@@ -51,6 +57,7 @@ MAX_DEPTH_HARD = 64
51
57
  MAX_NODES_DEFAULT = 500
52
58
 
53
59
 
60
+ # 生效条件:edge 为 dict 时按 relation_type→relation→type 顺序取首个真值、非 dict 时 rel 记为 None,两者统一返回 str(rel or "").strip().lower()——键缺失或全为假值时得空串。
54
61
  def edge_rel(edge):
55
62
  """取边的 relation_type(兼容 dict / 字符串两种写法),统一小写。"""
56
63
  if isinstance(edge, dict):
@@ -60,6 +67,7 @@ def edge_rel(edge):
60
67
  return str(rel or "").strip().lower()
61
68
 
62
69
 
70
+ # 生效条件:edge 为 dict 时取 target or target_id(前者假值回落后者),该值非 None 则返回其 str().strip()、为 None 返回 None;edge is None 返回 None;其余(裸字符串等)返回 str(edge).strip() 或空白串时 None。
63
71
  def edge_target(edge):
64
72
  """取边的目标节点 id(兼容 target / target_id / 裸字符串)。"""
65
73
  if isinstance(edge, dict):
@@ -70,6 +78,7 @@ def edge_target(edge):
70
78
  return str(edge).strip() or None
71
79
 
72
80
 
81
+ # 生效条件:base 取 EDGE_WEIGHTS.get(edge_rel(edge), DEFAULT_EDGE_WEIGHT);edge 为 dict 时 conf 为 float(edge.get("confidence", 1.0))(缺该键得 1.0,值不可转 float 如 None 触发 TypeError/ValueError 时也回落 1.0),非 dict 时 conf 恒为 1.0,返回 round(base * max(0.0, min(1.0, conf)), 6);
73
82
  def edge_weight(edge):
74
83
  """边权重 = 类型 base × 边置信度(缺失置信度视为 1.0 的已声明边)。"""
75
84
  base = EDGE_WEIGHTS.get(edge_rel(edge), DEFAULT_EDGE_WEIGHT)
@@ -82,6 +91,7 @@ def edge_weight(edge):
82
91
  return round(base * max(0.0, min(1.0, conf)), 6)
83
92
 
84
93
 
94
+ # 生效条件:edge 非 dict 时返回 "";edge 为 dict 时按 ("condition","conditions","条件") 顺序取第一个真值(list/tuple 先以 ";" 连接其中 str(x).strip() 非空的项,连接结果为空则视为假值跳过该键)并返回 str(v).strip();三键均无真值且 edge.get("condition_space") 为 dict 时返回 condition_space_text(cs, require_full=False);否则返回 "";
85
95
  def edge_condition(edge):
86
96
  """边的条件标注:条件链上「这一跳在什么条件下成立」。"""
87
97
  if not isinstance(edge, dict):
@@ -101,6 +111,7 @@ def edge_condition(edge):
101
111
  return ""
102
112
 
103
113
 
114
+ # 生效条件:cg.get(nid) 为假值(该节点缺失或为空)时返回 [];否则以 node.get("frontmatter") or {} 与 node.get("content") or "" 调 _declared_conditions,返回其正向条件列表 pos;
104
115
  def node_conditions(cg, nid):
105
116
  """节点自己声明的生效条件(CCG `# 生效条件:` 等三处来源合并)。"""
106
117
  node = cg.get(nid)
@@ -112,6 +123,7 @@ def node_conditions(cg, nid):
112
123
  return pos
113
124
 
114
125
 
126
+ # 生效条件:cg 已有 _chain_adj 且其 [0] 等于 bool(include_hierarchy) 时直接返回缓存的 [1];否则以 cg.index["nodes"](无 index 或无该键时视为无节点)逐节点收集 frontmatter.edges 中 edge_target 非空的出边,include_hierarchy 为真时再为 subgraph.nodes 各合成一条 relation_type="part_of"、confidence=1.0 的层级边,仅对有出边的 nid 建表,写回 cg._chain_adj=(bool(include_hierarchy), adj) 后返回 adj;
115
127
  def adjacency(cg, include_hierarchy=True):
116
128
  """出邻接表:nid → [(target_id, edge_dict)]。
117
129
 
@@ -146,6 +158,7 @@ def adjacency(cg, include_hierarchy=True):
146
158
  return adj
147
159
 
148
160
 
161
+ # 生效条件:调用即把 cg._chain_adj 置为 None(赋值抛异常时静默忽略),无返回值;
149
162
  def invalidate_cache(cg):
150
163
  """写入/删除节点后丢弃邻接缓存(与 subgraph.invalidate_cache 成对调用)。"""
151
164
  try:
@@ -154,6 +167,7 @@ def invalidate_cache(cg):
154
167
  pass
155
168
 
156
169
 
170
+ # 生效条件:对 adj 的每个 src→[(tgt, e)] 逐条把 (src, e) 追加到 rev[tgt](同 tgt 多次追加保持出现顺序),adj 为空字典时 rev 为空字典并返回;
157
171
  def _reverse(adj):
158
172
  rev = {}
159
173
  for src, outs in adj.items():
@@ -162,6 +176,7 @@ def _reverse(adj):
162
176
  return rev
163
177
 
164
178
 
179
+ # 生效条件:start_id 起步迭代 DFS——max_depth 非 None 时先钳为 max(0, min(int(max_depth), MAX_DEPTH_HARD)),rels 为 (relation_types or ()) 的小写元组(None 或空则不作类型过滤),direction=="in" 时邻接表改用 _reverse(adjacency(cg, include_hierarchy)),每跳要求 rel∈rels(rels 非空时)、tgt 不在 seen、weight*edge_weight(e) ≥ min_weight,链在 max_depth 为 None 或 len(hops+[hop]) ≤ max_depth 时收入、在 max_depth 为 None 或 len(hops+[hop]) < max_depth 时继续下探,首跳且边无显式条件时条件回退 start_id 的 node_conditions,扩展节点数受 max_nodes、收链数受 max_chains 限制,sort=="length" 时按 (depth, -avg_weight) 排序否则按 (-weight, -depth) 排序,返回 chains[:max_chains];
165
180
  def walk(cg, start_id, relation_types=CAUSAL_TYPES, max_depth=MAX_DEPTH_DEFAULT,
166
181
  direction="out", max_nodes=MAX_NODES_DEFAULT, min_weight=0.0,
167
182
  max_chains=200, include_hierarchy=True, sort="strength"):
@@ -218,13 +233,18 @@ def walk(cg, start_id, relation_types=CAUSAL_TYPES, max_depth=MAX_DEPTH_DEFAULT,
218
233
  stack.append((tgt, seen | {tgt}, nhop, nw))
219
234
  if not extended and not hops:
220
235
  continue
236
+ # 终键 tuple(nodes):图遍历序取决于邻接结构的枚举序,并列(同 depth/
237
+ # weight/avg_weight)时若无终键,截断结果随索引构建路径漂移。
221
238
  if sort == "length": # 对齐 AEIS infer_causal_paths 的 Occam 偏好
222
- chains.sort(key=lambda c: (c["depth"], -c["avg_weight"]))
239
+ chains.sort(key=lambda c: (c["depth"], -c["avg_weight"],
240
+ tuple(c["nodes"])))
223
241
  else:
224
- chains.sort(key=lambda c: (-c["weight"], -c["depth"]))
242
+ chains.sort(key=lambda c: (-c["weight"], -c["depth"],
243
+ tuple(c["nodes"])))
225
244
  return chains[:max_chains]
226
245
 
227
246
 
247
+ # 生效条件:kw 未含 relation_types 时先注入 CAUSAL_TYPES,再以 walk(cg, start_id, **kw) 的每条链逐跳渲染(跳条件为空串则显示「(未声明条件)」),返回 {"start": start_id, "count": 渲染链数, "chains": rendered};
228
248
  def explain(cg, start_id, **kw):
229
249
  """人类可读的链式解释:「什么条件下 → 发生什么」。"""
230
250
  kw.setdefault("relation_types", CAUSAL_TYPES)
@@ -242,6 +262,7 @@ def explain(cg, start_id, **kw):
242
262
  return {"start": start_id, "count": len(rendered), "chains": rendered}
243
263
 
244
264
 
265
+ # 生效条件:seeds 为 dict 时取其 items、否则取 list(seeds or [])(假值 seeds 得空列表,返回空 best),逐 (sid, s0) 跳过 sid 为假值或 float(s0) 抛 TypeError/ValueError 的项,对 walk(cg, sid, relation_types, max_depth, max_nodes, max_chains, include_hierarchy) 每条链取 nodes[-1] 为 nid(nid==sid 则跳过)并按 s0*链 weight*decay^depth 对每个 nid 只保留最高分,返回 best;
245
266
  def expand_from_seeds(cg, seeds, relation_types=CHAIN_TYPES_DEFAULT,
246
267
  max_depth=MAX_DEPTH_DEFAULT, decay=0.9,
247
268
  max_nodes=MAX_NODES_DEFAULT, max_chains=500,
@@ -277,4 +298,4 @@ def expand_from_seeds(cg, seeds, relation_types=CHAIN_TYPES_DEFAULT,
277
298
  if cur is None or sc > cur["score"]:
278
299
  best[nid] = {"score": round(sc, 6), "chain": c,
279
300
  "depth": c["depth"], "conditions": c["conditions"]}
280
- return best
301
+ return best
@@ -31,14 +31,37 @@ MAX_DOC = 400
31
31
  LANG_COMPILER = "compiler"
32
32
  LANG_WEAK = "other"
33
33
 
34
+ # --------------------------------------------------------------------------
35
+ # 渲染契约代际(版本戳)
36
+ # --------------------------------------------------------------------------
37
+ # 生效条件:`render` 的**产物形态**发生不兼容变化时 +1(形态不变的重构不 +1);
38
+ # 由 refindex 写入 frontmatter.code_ref.render_version(节点侧),由 selfreport
39
+ # 随常驻进程自报(进程侧),两侧同取本常量——**同源,无第二处硬编码**。
40
+ #
41
+ # 用途(第③道防线,防「旧契约静默覆盖重建成果」):
42
+ # ① 节点侧:`scripts/mdcg_verify_render_meta.py` 据 code_ref.render_version 机械
43
+ # 判定「节点由哪一代 render 产出」,不再只靠形态启发式(正文含元条件行);
44
+ # ② 进程侧:`scripts/mdcg_stale_servers.py` 据自报值判定活进程代际,堵住
45
+ # 「进程启动时间晚于源码 mtime 故 stale=False、却持旧 render」的盲区
46
+ # (AGENTS.md §5 运维注记的活体实证:旧契约把全量重建成果刷回 old_synth)。
47
+ #
48
+ # 代际史:
49
+ # 1 = 旧契约(npm 0.4.8 及以前):合成区产出 `# 生效条件:载体/位置:…`,
50
+ # 索引元条件冒用 CCG 字段名(合成即冒充)。
51
+ # 2 = 三分区契约(2026-09-19):源码 CCG 区置首 → 合成 CCG 区(不产出生效
52
+ # 条件行)→ 索引元信息区(`# 索引元条件:…` 非 CCG 字段名 + 位置行)。
53
+ RENDER_VERSION = 2
54
+
34
55
 
35
56
  # --------------------------------------------------------------------------
36
57
  # Python:AST 提取(精确)
37
58
  # --------------------------------------------------------------------------
59
+ # 生效条件:node 传入后,取 ast.get_docstring(node, clean=True) 的返回值,若该返回值为假值则回落空串,返回 strip 后截断到模块级 MAX_DOC 的文本;
38
60
  def _doc_of(node):
39
61
  return (ast.get_docstring(node, clean=True) or "").strip()[:MAX_DOC]
40
62
 
41
63
 
64
+ # 生效条件:lines 为源码行列表、lineno 为 1-based 定义行时,从 lines[lineno-2] 向上收集连续以 "#" 起始的行,遇空行且已收集到注释即停止,遇空行且未收集到注释则跳过继续,遇非注释非空行停止,返回按物理顺序排列的注释列表;lineno<=1 或初始无匹配时返回空列表;
42
65
  def _leading_comments(lines, lineno):
43
66
  """定义行前的连续注释(# ...)。"""
44
67
  out, i = [], lineno - 2
@@ -56,6 +79,55 @@ def _leading_comments(lines, lineno):
56
79
  return list(reversed(out))
57
80
 
58
81
 
82
+ # 生效条件:node 具有真值 body 属性时返回 body[0].lineno;否则(body 为 None/假值/缺属性)返回 node.lineno;
83
+ def _body_first_line(node):
84
+ """符号体首个语句的行号(1-based);无体 → 定义行本身(窗口为空)。"""
85
+ body = getattr(node, "body", None) or []
86
+ return body[0].lineno if body else node.lineno
87
+
88
+
89
+ # 生效条件:lines 为 source.split("\n") 得到的行列表、lineno 为 1-based 定义行、body_lineno 为 1-based 体首语句行时,在 end=max(lineno, body_lineno-1) 下扫描 lines[lineno:end],收集 strip 后以 "#" 起始的行并返回;body_lineno-1 <= lineno 时返回空列表;
90
+ def _body_comments(lines, lineno, body_lineno):
91
+ """符号**体内首个语句之前**的连续 `#` 注释(定义行紧下方,声明头区)。
92
+
93
+ 这是与 `_leading_comments`(定义行**之上**)并列的**第二个窗口**:
94
+
95
+ · 既有白箱单元库 104+ 处把 CCG 注释块写在**这里**
96
+ (例:`md_cg/whitebox_kb/wisdom/python_code_units.py` 的模板
97
+ `def tokenize(src):` 下一行即 ` # 生效条件:参数 src 合法`);
98
+ · 本函数是 body 窗口的**唯一真源**——`whitebox_kb/wisdom/verifier._ccg_block`
99
+ 委托此处(历史文档里那句「与 `codeindex._body_comments` 同款语义」曾是
100
+ **悬空引用**:该名当时并不存在)。
101
+
102
+ 参数:`lines`=源码行列表(`source.split("\\n")`);`lineno`=定义行(1-based);
103
+ `body_lineno`=体首个语句行(1-based)。窗口 = `lines[lineno : body_lineno-1]`
104
+ (0-based 切片:定义行之后 → 体首语句之前),只收 `#` 起始行。
105
+ 语法上该窗口**结构性地只可能含注释/空行/docstring**——体首语句之前的区域。
106
+ """
107
+ start = lineno # 0-based 索引 → 定义行的下一行
108
+ end = max(start, body_lineno - 1)
109
+ out = []
110
+ for ln in lines[start:end]:
111
+ s = ln.strip()
112
+ if s.startswith("#"):
113
+ out.append(s)
114
+ return out
115
+
116
+
117
+ # 生效条件:lines 为源码行列表且 node 含 lineno 时,返回 _leading_comments(lines, node.lineno) 与 _body_comments(lines, node.lineno, _body_first_line(node)) 的拼接结果(leading 在前、body 在后);
118
+ def _symbol_comments(lines, node):
119
+ """符号的「源码 CCG 区」= leading 窗口 + body 窗口,**按物理行序**合并。
120
+
121
+ 不发明额外优先级:两个窗口在源文件里的物理先后天然确定(leading 在定义行
122
+ 之上、body 在其下),而检索侧 `mdcos._ccg_field` 取**首个**匹配——于是
123
+ 「靠前者胜出」与「物理序」是同一件事,确定性可复算。
124
+ 单窗口文件的行为与改造前逐字一致(只多收 body 窗口)。
125
+ """
126
+ return (_leading_comments(lines, node.lineno)
127
+ + _body_comments(lines, node.lineno, _body_first_line(node)))
128
+
129
+
130
+ # 生效条件:source 与 node 传入后,取 ast.get_source_segment(source, node) 的返回值,若抛 ValueError/TypeError 或返回假值则 seg 为空串,返回 seg.split("\n",1)[0].strip()[:200];
59
131
  def _sig(source, node):
60
132
  try:
61
133
  seg = ast.get_source_segment(source, node) or ""
@@ -64,6 +136,7 @@ def _sig(source, node):
64
136
  return seg.split("\n", 1)[0].strip()[:200]
65
137
 
66
138
 
139
+ # 生效条件:tree 为 AST 根节点时,调用嵌套 rec(tree, "") 按 ast.iter_child_nodes 源码顺序递归产出 (定义节点, 所属类名);ClassDef 自身以当前 parent 产出并对其内部递归改用类名,FunctionDef/AsyncFunctionDef 以当前 parent 产出并保持 parent,其他节点递归保持 parent;
67
140
  def _walk_defs(tree):
68
141
  """按**源码顺序**产出 (定义节点, 所属类名)。
69
142
 
@@ -71,6 +144,7 @@ def _walk_defs(tree):
71
144
  父级归属是「子功能」与「不适用条件」两项的判定依据(同名方法必须能区分
72
145
  是哪个类的),不能省。
73
146
  """
147
+ # 生效条件:node 为 AST 节点、parent 为当前所属类名字符串时,按 ast.iter_child_nodes(node) 顺序递归产出 (定义节点, 所属类名):ClassDef 以 parent 产出并递归改用 child.name,FunctionDef/AsyncFunctionDef 以 parent 产出并递归保持 parent,其他节点递归保持 parent;
74
148
  def rec(node, parent):
75
149
  for child in ast.iter_child_nodes(node):
76
150
  if isinstance(child, ast.ClassDef):
@@ -84,6 +158,7 @@ def _walk_defs(tree):
84
158
  return rec(tree, "")
85
159
 
86
160
 
161
+ # 生效条件:source 可被 ast.parse 成功解析时,返回首项为 module 条目(path、name=os.path.basename(path) or "<module>"、lineno=1、end=len(source.split("\n"))、doc=_doc_of(tree))后接 _walk_defs(tree) 各定义条目的列表;source 触发 SyntaxError 时抛 ValueError(f"{path}:{exc.lineno}: {exc.msg}");
87
162
  def _extract_python(source, path):
88
163
  try:
89
164
  tree = ast.parse(source)
@@ -101,7 +176,7 @@ def _extract_python(source, path):
101
176
  "path": path, "name": node.name, "kind": kind, "parent": parent,
102
177
  "lineno": node.lineno, "end": getattr(node, "end_lineno", node.lineno),
103
178
  "sig": _sig(source, node), "doc": _doc_of(node),
104
- "comments": _leading_comments(lines, node.lineno)})
179
+ "comments": _symbol_comments(lines, node)})
105
180
  return items
106
181
 
107
182
 
@@ -118,6 +193,7 @@ _JS_DEF = re.compile(
118
193
  _JS_MODULE_SCOPE_ONLY = ("const", "type", "enum")
119
194
 
120
195
 
196
+ # 生效条件:lines 为源码行列表、lineno 为 1-based 定义行时,从 lines[lineno-2] 向上收集连续以 "//" 开头的行注释,或遇到 strip 后以 "*/" 结尾的行时向上收集到首个 strip 后以 "/*" 开头的行(含该行)作为块注释;lookback 默认 25 限制收集行数,lookback=0 时循环不进入并返回空列表;遇空行且已有收集即停止,空行且未收集则跳过,其他行停止;
121
197
  def _leading_js_comments(lines, lineno, lookback=25):
122
198
  """定义行前的连续行注释块,或紧邻的 /** ... */ 块。"""
123
199
  out, i = [], lineno - 2
@@ -146,6 +222,7 @@ def _leading_js_comments(lines, lineno, lookback=25):
146
222
  return list(reversed(out))
147
223
 
148
224
 
225
+ # 生效条件:对 source 用 _JS_DEF.finditer 命中项生成条目(首项模块条目 name 为 os.path.basename(path) or "<module>"),跳过 kind 属于 _JS_MODULE_SCOPE_ONLY 且 indent 组非空的命中;其余命中按出现顺序取 lineno、kind、name、sig,end 为下一命中行号减一或 len(source.split("\n")) 且不小于 lineno,comments 由 _leading_js_comments(lines, lineno) 生成。
149
226
  def _extract_weak(source, path):
150
227
  """正则弱提取:返回条目,`end` 为**上界**(到下一个定义之前),不保证精确。"""
151
228
  lines = source.split("\n")
@@ -182,6 +259,7 @@ EXTRACTORS = {
182
259
  SUFFIX = tuple(sorted(EXTRACTORS))
183
260
 
184
261
 
262
+ # 生效条件:lines 为行列表、lineno 与 end 为 1-based 行号时,对 "\n".join(lines[max(0, lineno-1):max(0, end)]) 的 UTF-8 字节求 sha1,返回其十六进制前 12 位;
185
263
  def region_hash(lines, lineno, end):
186
264
  """被引用行的 sha1 前 12 位(变更探测用,非内容寻址)。
187
265
 
@@ -192,6 +270,7 @@ def region_hash(lines, lineno, end):
192
270
  return hashlib.sha1(seg.encode("utf-8")).hexdigest()[:12]
193
271
 
194
272
 
273
+ # 生效条件:source 与 path 传入后,ext=suffix or os.path.splitext(path)[1].lower();当 ext 存在于模块级 EXTRACTORS 时,用对应 fn(source, path) 抽取并给每个条目补 lang/precise/basis/hash(hash 由 region_hash(lines, it["lineno"], it["end"]) 算)后返回;ext 不在 EXTRACTORS 时抛 ValueError(f"无提取器(suffix={ext or '<none>'})");
195
274
  def extract(source, path="", suffix=None):
196
275
  """抽取一个文件的条目;按后缀分派提取器。语法错误抛 ValueError。
197
276
 
@@ -213,15 +292,18 @@ def extract(source, path="", suffix=None):
213
292
  return items
214
293
 
215
294
 
295
+ # 生效条件:item 为条目字典时,path=item.get("path") or ""、top=path.split("/")[0] or ".",按 item.get("precise", True)(缺键默认 True,键存在假值走弱提取)选择 LANG_COMPILER 或 LANG_WEAK 方法文本,返回 observation_position 用 top、time_window 用 nodefile.FULL_TIME_WINDOW_MIN 与 nodefile.FULL_TIME_WINDOW_MAX、observation_tool 用方法文本、existence_constraint 含 path 的四槽字典;
216
296
  def condition_space(item):
217
297
  """条目 → 条件空间四槽(纯函数,**唯一来源**)。
218
298
 
219
- 为什么必须与 `render` 同源:正文的 `# 生效条件:` 行与 frontmatter 的
299
+ 为什么必须与 `render` 同源:正文的 `# 索引元条件:` 行与 frontmatter 的
220
300
  `condition_space` 一旦各写一套,就会出现「正文有声明、条件空间是空的」
221
301
  ——`nodefile.condition_space_text(require_full=True)` 只看 frontmatter,
222
302
  于是节点**存得进、判得了,条件空间却没声明**。改造前正是这样:正文写
223
303
  「大域=X;检索…时」(第三种方言),frontmatter 只写 `observation_position`
224
304
  **单槽**。单槽不是生效条件(见 nodefile.CONDITION_SLOTS_REQUIRED),
305
+ 该四槽在正文里由「索引元条件」行承载(**不再**占用「生效条件」字段——
306
+ Phase 0 契约裁决,见 nodefile.INDEX_META_MARK),
225
307
  故本函数按四槽齐备产出,供 `render` 与 `refindex.add_items` 共用。
226
308
 
227
309
  时间槽用**全时窗哨兵**而非 `mdcg.add` 缺省补的「写入时刻锚定 1 小时窗」:
@@ -244,8 +326,9 @@ def condition_space(item):
244
326
  }
245
327
 
246
328
 
329
+ # 生效条件:item 为含 "name"、"kind"、"path"、"lineno"、"end" 键的条目字典时(缺这些必需键会 KeyError),返回由 item.get("comments") 的源码 CCG 区、合成 CCG 区、索引元信息区依次拼接的正文;parent/doc/comments/sig 按 item.get 缺键或假值回落,precise 缺键默认 True、键存在假值走弱提取,item["lineno"]/item["end"] 用于 basis 与位置行;
247
330
  def render(item):
248
- """条目 → CCG 6 行正文(可被 search 命中,不含实现)。
331
+ """条目 → 正文三分区:源码 CCG 区(人工优先)→ 合成 CCG 区 → 索引元信息区。
249
332
 
250
333
  **必须渲染成 CCG 格式**,这是本模块最容易踩的坑:
251
334
  `judge_qualification` 第一步就查 `ccg_completeness` 的 5 要素
@@ -255,6 +338,16 @@ def render(item):
255
338
  `# path::name` / `# sig` / `# doc:` 这类非 CCG 行,于是**所有代码节点
256
339
  恒定 BLINDSPOT**:存得进、判不了、检索不到(与「目标节点的 CCG 渲染」
257
340
  是同一策略,见 mdcg.py 的对应注释)。
341
+
342
+ Phase 0 修复(行序压制 + 字段语义分家;契约见
343
+ docs/mdcg/代码评审与条件化注释_契约_v0.1.md):
344
+ ① **源码 CCG 区置首**——mdcos._ccg_field 取**首个**匹配,置首即
345
+ 「人工优先」的确定性序:人工声明的生效条件不再被合成行压制;
346
+ ② 合成区**不再产出生效条件行**——索引元条件不是功能前置条件
347
+ (裁定见 nodefile.INDEX_META_MARK)。故源码未声明的条目会**诚实地
348
+ 缺该要素(BLINDSPOT)**,而不是被元条件冒充成 DEFER;
349
+ ③ 索引元信息区改用非 CCG 字段名(索引元条件行 + 位置行),两个语义
350
+ 不再挤同一个字段名(可机械判:nodefile.is_ccg_mark)。
258
351
  """
259
352
  name = item["name"]
260
353
  kind = item["kind"]
@@ -270,27 +363,37 @@ def render(item):
270
363
  else:
271
364
  basis = (f"{LANG_WEAK}(正则弱提取,未过编译器;区间为**上界**,"
272
365
  f"以 op=ref 回读为准:{path} L{item['lineno']}-L{item['end']})")
273
- lines = [
366
+ # ---- 三分区组装(顺序即语义,不许随手改)------------------------------
367
+ # ① 源码 CCG 区:人工/源码声明逐字保留,**置首**取得「首个匹配」优先权
368
+ # ② 合成 CCG 区:机械补齐 5 要素,保证 ccg_completeness 不因缺行整体失效
369
+ # ③ 索引元信息区:非 CCG 字段名 + 位置行(与 CCG_MARKS 零重名)
370
+ lines = ["# " + c for c in comments]
371
+ lines += [
274
372
  f"# 功能名:{name}({kind})",
275
- f"# 生效条件:{nodefile.condition_space_text(condition_space(item))}",
276
373
  f"# 子功能:{parent + '.' if parent else ''}{sub[:MAX_DOC]}",
277
374
  f"# 执行:{sig}",
278
375
  f"# 验证方式:{basis}",
279
376
  "# 不适用条件:其它大域的**同名**符号(同名不同域时以 path 区分;"
280
377
  f"本条目属于 {path})",
378
+ # 索引元条件**不占用**生效条件字段:它是「条目在何处/何时可被观测」,
379
+ # 不是「这段代码在何种输入下正确」。合成即冒充(nodefile.INDEX_META_MARK)。
380
+ f"# {nodefile.INDEX_META_MARK}:"
381
+ + nodefile.condition_space_text(condition_space(item),
382
+ require_full=False),
281
383
  f"# 位置:{path}:{item['lineno']}-{item['end']}"
282
384
  f"({item.get('lang')},precise={bool(item.get('precise', True))})",
283
385
  ]
284
- lines.extend("# " + c for c in comments)
285
386
  return "\n".join(lines)
286
387
 
287
388
 
389
+ # 生效条件:item 为含 "path" 与 "name" 键的字典时(缺任一键会 KeyError),返回 "code_" 加 (item["path"] + "::" + item["name"]).encode("utf-8") 的 sha1 十六进制前 12 位;
288
390
  def node_id(item):
289
391
  """稳定 id:path::name 的短哈希(重复索引幂等)。"""
290
392
  key = (item["path"] + "::" + item["name"]).encode("utf-8")
291
393
  return "code_" + hashlib.sha1(key).hexdigest()[:12]
292
394
 
293
395
 
396
+ # 生效条件:skip_dirs 传入后,遍历 (skip_dirs or ()) 把每项 str(raw).strip().replace("\\","/").strip("/"),空串跳过;含 "/" 的加入 paths,不含 "/" 的加入 names;若归一化后无规则返回 (None, []),否则返回 (hit, rules),其中 hit(rel_dir, base) 在 base 命中 names 或 rel_dir 等于/前缀匹配 paths 中某条加 "/" 时为 True;
294
397
  def skip_matcher(skip_dirs):
295
398
  """把调用方的 `skip_dirs` 编译成「该子目录是否排除」的判定 `hit(rel_dir, base)`。
296
399
 
@@ -320,6 +423,7 @@ def skip_matcher(skip_dirs):
320
423
  if not rules:
321
424
  return None, []
322
425
 
426
+ # 生效条件:在 skip_matcher 返回的闭包中,rel_dir 与 base 传入后,若 base 命中由 skip_dirs 归一化出的不含 "/" 的目录名集合 names 则返回 True;否则若 rel_dir 等于或以其某个含 "/" 的路径规则 paths 加 "/" 为前缀则返回 True;两者都不满足返回 False;
323
427
  def hit(rel_dir, base):
324
428
  if base in names:
325
429
  return True
@@ -328,6 +432,7 @@ def skip_matcher(skip_dirs):
328
432
  return hit, rules
329
433
 
330
434
 
435
+ # 生效条件:当 root 为可 os.walk 的目录时返回 (items, errors, stats);patterns 为 None 时按模块常量 SUFFIX 取后缀,命中 max_files 或 max_items 上限则在 stats['truncated'] 上报截断,fresh 为 None 时逐文件读盘。
331
436
  def index_dir(root, patterns=None, max_files=500, max_items=2000,
332
437
  fresh=None, on_file=None, skip_dirs=None):
333
438
  """按大域(目录)遍历代码,产出 `(items, errors, stats)`。零 LLM。
@@ -350,11 +455,25 @@ def index_dir(root, patterns=None, max_files=500, max_items=2000,
350
455
  pats = tuple(patterns or SUFFIX)
351
456
  hit_skip, skip_rules = skip_matcher(skip_dirs)
352
457
  items, errors, files = [], [], 0
458
+ hit_files = 0
353
459
  seen_suffix = set()
354
460
  stats = {"root": root, "patterns": list(pats), "files": 0, "truncated": False,
355
461
  "truncated_reason": "", "max_files": max_files, "max_items": max_items,
356
462
  "skipped_suffixes": [], "skipped_unchanged": 0,
357
- "skip_dirs": list(skip_rules), "skipped_dirs": []}
463
+ "skip_dirs": list(skip_rules), "skipped_dirs": [],
464
+ # 截断**可复算**:命中(后缀匹配)文件数与本轮已产出条目数。
465
+ # 与 truncated_reason 一起读,调用方才能核对「差多少」而不是只看到"被截断了"。
466
+ "hit_files": 0, "indexed_items": 0}
467
+
468
+ # 生效条件:无参闭包,只在本次扫库作用域内可调用;把 files / hit_files / indexed_items / skipped_suffixes / skipped_dirs 一次性落进 stats,三处 return 共用同一口径;
469
+ def _snap():
470
+ """把「截断相关」计数一次性落进 stats(三处 return 共用,避免各处口径漂移)。"""
471
+ stats["files"] = files
472
+ stats["hit_files"] = hit_files
473
+ stats["indexed_items"] = len(items)
474
+ stats["skipped_suffixes"] = sorted(
475
+ s for s in seen_suffix if s and s not in pats)[:12]
476
+
358
477
  for dirpath, dirnames, filenames in os.walk(root):
359
478
  rel_dir = os.path.relpath(dirpath, root).replace("\\", "/")
360
479
  if rel_dir == ".":
@@ -369,21 +488,22 @@ def index_dir(root, patterns=None, max_files=500, max_items=2000,
369
488
  stats["skipped_dirs"].append(child)
370
489
  continue
371
490
  keep.append(d)
372
- dirnames[:] = keep
491
+ # 目录序**必须确定性**:os.walk 给出的 dirnames 顺序由文件系统决定,
492
+ # 同一次输入两次运行可能不同 → 索引结果不可复算。排序后 walk 顺序唯一。
493
+ dirnames[:] = sorted(keep)
373
494
  for fn in sorted(filenames):
374
495
  ext = os.path.splitext(fn)[1].lower()
375
496
  seen_suffix.add(ext)
376
497
  if not fn.lower().endswith(pats):
377
498
  continue
499
+ hit_files += 1
378
500
  if files >= max_files or len(items) >= max_items:
379
501
  stats["truncated"] = True
380
502
  stats["truncated_reason"] = (
381
503
  f"files={files}>=max_files={max_files}"
382
504
  if files >= max_files else
383
505
  f"items={len(items)}>=max_items={max_items}")
384
- stats["files"] = files
385
- stats["skipped_suffixes"] = sorted(
386
- s for s in seen_suffix if s and s not in pats)[:12]
506
+ _snap()
387
507
  return items, errors, stats
388
508
  files += 1
389
509
  fp = os.path.join(dirpath, fn)
@@ -404,12 +524,9 @@ def index_dir(root, patterns=None, max_files=500, max_items=2000,
404
524
  stats["truncated"] = True
405
525
  stats["truncated_reason"] = (
406
526
  f"items={len(items)}>=max_items={max_items}")
407
- stats["files"] = files
408
- stats["skipped_suffixes"] = sorted(
409
- s for s in seen_suffix if s and s not in pats)[:12]
527
+ _snap()
410
528
  return items, errors, stats
411
529
  except (OSError, UnicodeDecodeError, ValueError) as exc:
412
530
  errors.append(f"{rel}: {exc}")
413
- stats["files"] = files
414
- stats["skipped_suffixes"] = sorted(s for s in seen_suffix if s and s not in pats)[:12]
415
- return items, errors, stats
531
+ _snap()
532
+ return items, errors, stats