@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/predict.py CHANGED
@@ -58,9 +58,34 @@ W_BOUNDARY = 0.20
58
58
  W_VERIFICATION = 0.25
59
59
  W_BALANCE = 0.15
60
60
 
61
+ # D_meta 第五维(opt-in,方案 §2.3):默认 0 = 不参与 composite、不落键、
62
+ # SORT_KEYS 不扩张(默认返回与四维时代逐字节一致,默认零变更纪律)。
63
+ # 显式启用:PREDICTION_META_DIM=<权重>(>0 才生效)
64
+ # PREDICTION_META_PROXY=<代理名>(缺省 unmodeled_growth;**只取单一
65
+ # 代理**——三代理加权合成违反智能论3.4 DEV-002a)
66
+ # 纪律:导入期读一次环境变量,改值须重载模块;catalog().weights 同步扩张。
67
+ try:
68
+ W_META = float(os.environ.get("PREDICTION_META_DIM", "0") or 0.0)
69
+ except ValueError: # 非法值按关闭处理:默认零变更优先,不炸导入
70
+ W_META = 0.0
71
+ W_META = W_META if W_META > 0 else 0.0
72
+ META_PROXY = os.environ.get("PREDICTION_META_PROXY", "unmodeled_growth")
73
+
61
74
  SORT_KEYS = ("composite", "trend", "verification", "boundary", "balance")
75
+ if W_META > 0: # 第五维开启时才扩张排序键(默认零变更)
76
+ SORT_KEYS = SORT_KEYS + ("meta_pressure",)
62
77
  LOG_FILE = "_prediction.jsonl"
63
78
 
79
+
80
+ # 生效条件:不适用(无必需形参与分支),恒返回四维权重的自描述 dict;仅当 W_META>0(PREDICTION_META_DIM 显式启用第五维)时追加 meta_pressure 键;
81
+ def _weights():
82
+ """自描述权重:默认四维逐字节不变,第五维 opt-in 时同步扩张。"""
83
+ w = {"trend": W_TREND, "boundary": W_BOUNDARY,
84
+ "verification": W_VERIFICATION, "balance": W_BALANCE}
85
+ if W_META > 0:
86
+ w["meta_pressure"] = W_META
87
+ return w
88
+
64
89
  # 锚点解析纪律(盲区 → 锚点):推断脚手架与负记忆都不得充当锚点。
65
90
  # - `gap_hint`(待补线索)与 `scene`(情景重构产物)是「推断得出的引子/回放」,
66
91
  # 本身不构成可起推的事实;尤其 gap_hint 会把盲区描述逐字抄进自己的
@@ -75,14 +100,17 @@ ANCHOR_SKIP_LAYERS = ("unresolved", "rejected")
75
100
 
76
101
  # ---------------------------------------------------------------- 基础
77
102
 
103
+ # 生效条件:传入 cg 具 index 键且其 'nodes' 为非空映射时返回该映射,否则返回空字典 {};
78
104
  def _nodes(cg):
79
105
  return ((getattr(cg, "index", None) or {}).get("nodes") or {})
80
106
 
81
107
 
108
+ # 生效条件:传入 cg 具 root 属性时返回 root 与模块级常量 LOG_FILE 的路径拼接,缺 root 则以 '.' 拼接;
82
109
  def log_path(cg):
83
110
  return os.path.join(getattr(cg, "root", "."), LOG_FILE)
84
111
 
85
112
 
113
+ # 生效条件:传入 cg 与 rec 时向 log_path(cg) 追加一条 JSONL 记录,OSError 被吞掉且无返回值;
86
114
  def _append(cg, rec):
87
115
  try:
88
116
  append_jsonl(log_path(cg), rec)
@@ -90,6 +118,7 @@ def _append(cg, rec):
90
118
  pass
91
119
 
92
120
 
121
+ # 生效条件:传入 cg 可读出 JSONL 记录时返回记录列表,读取抛 OSError 或 ValueError 时返回 [],limit 为正时仅返回末尾 limit 条;
93
122
  def _read_log(cg, limit=0):
94
123
  try:
95
124
  recs = list(read_jsonl(log_path(cg)))
@@ -100,18 +129,21 @@ def _read_log(cg, limit=0):
100
129
  return recs
101
130
 
102
131
 
132
+ # 生效条件:传入 cg 的留痕中存在 type=='feedback' 的记录时返回其 hit 布尔序列末尾 limit 条(limit 默认常量 HIT_HISTORY_MAX),无此类记录则返回空列表;
103
133
  def _hit_history(cg, limit=HIT_HISTORY_MAX):
104
134
  """D-006 命中历史(持久化 · 差异 2):只取 feedback 记录。"""
105
135
  return [bool(r.get("hit")) for r in _read_log(cg)
106
136
  if r.get("type") == "feedback"][-int(limit):]
107
137
 
108
138
 
139
+ # 生效条件:传入 cg 与 nid 时返回邻接表中 nid 的出边列表 [(目标 id, 边字典)],该键无出边则为 [];
109
140
  def _out_edges(cg, nid):
110
141
  """出边(含层级边):[(target_id, edge_dict)],复用 chain 邻接缓存。"""
111
142
  from . import chain
112
143
  return list((chain.adjacency(cg).get(nid) or []))
113
144
 
114
145
 
146
+ # 生效条件:传入 cg 与 nid 时返回邻接表中所有以 nid 为目标的源节点集合,无入边则为空集;
115
147
  def _in_sources(cg, nid):
116
148
  """入边来源集合(父节点):用于 D-002「共同父节点」结构模式判定。"""
117
149
  from . import chain
@@ -124,6 +156,7 @@ def _in_sources(cg, nid):
124
156
  return srcs
125
157
 
126
158
 
159
+ # 生效条件:传入 edge 的 'confidence' 可转 float 时返回裁剪到 [0.0,1.0] 的值,取键失败或转换抛 AttributeError/TypeError/ValueError 时返回 1.0;
127
160
  def _edge_conf(edge):
128
161
  try:
129
162
  return max(0.0, min(1.0, float(edge.get("confidence", 1.0))))
@@ -133,6 +166,7 @@ def _edge_conf(edge):
133
166
 
134
167
  # ---------------------------------------------------------------- D-002 过滤门
135
168
 
169
+ # 生效条件:causal_link 成立条件为 a_id 的出边中存在目标 b_id 且其关系类型属于模块级常量 CAUSAL_BRANCH_TYPES,成立返回 True,否则返回 False;
136
170
  def has_causal_link(cg, a_id, b_id):
137
171
  """直接因果/时序边:A → B 已声明(直通,无需过滤)。"""
138
172
  from . import chain
@@ -142,11 +176,13 @@ def has_causal_link(cg, a_id, b_id):
142
176
  return False
143
177
 
144
178
 
179
+ # 生效条件:传入 cg、a_id、b_id 时,a_id 与 b_id 的入边来源集合交集非空返回 True,交集为空返回 False;
145
180
  def has_structural_pattern(cg, a_id, b_id):
146
181
  """结构模式:A、B 共享父节点(可解释的间接关联 → 伪因果豁免)。"""
147
182
  return bool(_in_sources(cg, a_id) & _in_sources(cg, b_id))
148
183
 
149
184
 
185
+ # 生效条件:cg 具 attention_policy 且非 None、且 get_weights() 返回可取值的映射时返回 float(weights.get(node_id, 0.0)),策略缺失、取权重抛异常或转换失败时返回 0.0;
150
186
  def preference_weight(cg, node_id):
151
187
  """D-005:AttentionPolicy 适配器(duck-typed `get_weights()`)。
152
188
 
@@ -166,6 +202,7 @@ def preference_weight(cg, node_id):
166
202
  return 0.0
167
203
 
168
204
 
205
+ # 生效条件:cg/a_id/b_id 下 has_causal_link 成立返回 (True,'causal_link'),否则 has_structural_pattern 成立返回 (True,'structural_pattern'),否则 preference_weight(cg,b_id) 大于常量 PREFERENCE_THRESHOLD 返回 (True,'preference_weight'),三者皆不成立返回 (False,'rejected_semantic_only');
169
206
  def causal_gate(cg, a_id, b_id):
170
207
  """D-002 伪因果过滤门 → (准入?, 理由)。
171
208
 
@@ -185,6 +222,7 @@ def causal_gate(cg, a_id, b_id):
185
222
 
186
223
  # ---------------------------------------------------------------- 语义邻近
187
224
 
225
+ # 生效条件:cg.get(node_id) 的 content 去空后非空时以前 200 字符检索,返回相似度不低于常量 SEMANTIC_MIN_SIM 且非自身的至多 k 个 (nid, similarity);content 为空或检索抛异常时返回 [];
188
226
  def semantic_neighbors(cg, node_id, k=SEMANTIC_TOP_K):
189
227
  """语义邻近候选:[(node_id, similarity)]。
190
228
 
@@ -223,6 +261,7 @@ def semantic_neighbors(cg, node_id, k=SEMANTIC_TOP_K):
223
261
 
224
262
  # ---------------------------------------------------------------- D-001 分支
225
263
 
264
+ # 生效条件:传入 cg 与 node_id 时,其出边中关系类型属于常量 CAUSAL_BRANCH_TYPES 者直通为 causal 候选,semantic 为真时再并入经 causal_gate 放行的语义邻近候选,按 confidence 降序、node_id 升序返回;
226
265
  def branch_candidates(cg, node_id, semantic=True):
227
266
  """D-001 局部分支候选:因果/时序边直通 + 语义邻近(经 D-002 门)。"""
228
267
  from . import chain
@@ -254,6 +293,7 @@ def branch_candidates(cg, node_id, semantic=True):
254
293
 
255
294
  # ---------------------------------------------------------------- D-003 / D-004
256
295
 
296
+ # 生效条件:conf 可转 float 时裁剪到 [0,1] 得 c,按 base=1-c 返回 confidence=c 与裁剪到 [0,1] 的 [c-base*0.5, c+base*0.5] 区间,转换失败则按 c=0.0 计算;
257
297
  def _uncertainty(conf):
258
298
  """D-001 不确定带:base=1-conf,上下界 = conf ± base*0.5(AEIS 同式)。"""
259
299
  try:
@@ -267,6 +307,7 @@ def _uncertainty(conf):
267
307
  "method": "linear_local_approx"}
268
308
 
269
309
 
310
+ # 生效条件:传入 cg 与 path 且 path 非空时,返回其中 tags 含 'boundary' 或 has_neg_conditions,或 content 匹配「不适用|不确定|边界|盲区」的节点占比;path 为空返回 0.0;
270
311
  def _boundary_consistency(cg, path):
271
312
  """boundary 维:路径节点是否声明了适用边界/不确定条件(0-1)。"""
272
313
  if not path:
@@ -284,6 +325,7 @@ def _boundary_consistency(cg, path):
284
325
  return round(hit / len(path), 4)
285
326
 
286
327
 
328
+ # 生效条件:传入 route 时返回其 sources 与 relations 去重并集大小除以 4.0 且上限 1.0 的值,两键皆缺时返回 0.0;
287
329
  def _branch_diversity(route):
288
330
  """balance 维:路径覆盖的推理通道维度数 / 4。
289
331
 
@@ -295,6 +337,7 @@ def _branch_diversity(route):
295
337
  return round(min(1.0, len(dims) / 4.0), 4)
296
338
 
297
339
 
340
+ # 生效条件:route 的 'confs' 长度不少于 2 时,相邻差绝对值最大值不超过 0.35 返回 'smooth' 否则 'jump';长度不足 2 或无可算步长返回 'unknown';
298
341
  def extrapolation_validity(route):
299
342
  """D-003:局部线性外推有效性(smooth / jump / unknown)。"""
300
343
  confs = route.get("confs") or []
@@ -306,6 +349,7 @@ def extrapolation_validity(route):
306
349
  return "smooth" if max(abs(s) for s in steps) <= 0.35 else "jump"
307
350
 
308
351
 
352
+ # 生效条件:传入 cg 且 _hit_history(cg) 非空时返回其命中占比,序列为空时返回模块级常量 BASE_HIT_RATE;
309
353
  def hit_rate(cg):
310
354
  """历史命中率(无样本 → 基线 0.40,对齐 D-006)。"""
311
355
  h = _hit_history(cg)
@@ -316,6 +360,7 @@ def hit_rate(cg):
316
360
 
317
361
  # ---------------------------------------------------------------- P-T-73/74 通道贝叶斯
318
362
 
363
+ # 生效条件:传入 hits 序列时以 base*prior_k 与 (1-base)*prior_k 为先验(prior_k 默认常量 PRIOR_STRENGTH、base 默认常量 BASE_HIT_RATE),按命中数 k 与总数 n 返回 alpha/beta/mean/std/ci95/samples/hits;hits 为空即为纯先验,mean 等于 base;
319
364
  def beta_posterior(hits, prior_k=PRIOR_STRENGTH, base=BASE_HIT_RATE):
320
365
  """Beta-Bernoulli 后验(纯函数):命中序列 → 后验参数与区间。
321
366
 
@@ -346,6 +391,7 @@ def beta_posterior(hits, prior_k=PRIOR_STRENGTH, base=BASE_HIT_RATE):
346
391
  "samples": n, "hits": k}
347
392
 
348
393
 
394
+ # 生效条件:传入 cg 时把 type=='feedback' 的记录按 channel 字段(缺失归 'unlabeled')分组为 {channel: [hit...]},仅取末尾 limit 条(limit 默认常量 HIT_HISTORY_MAX);
349
395
  def channel_history(cg, limit=HIT_HISTORY_MAX):
350
396
  """feedback 留痕按通道分组(P-T-74 通道级可信度)→ {channel: [hit...]}。
351
397
 
@@ -361,6 +407,7 @@ def channel_history(cg, limit=HIT_HISTORY_MAX):
361
407
  return out
362
408
 
363
409
 
410
+ # 生效条件:channel 非 None 时返回该通道(无记录即先验)的 beta_posterior 并附 channel 键,channel 为 None 时返回 {'all': 全量后验, 'channels': 各通道后验};
364
411
  def channel_posterior(cg, channel=None, limit=HIT_HISTORY_MAX):
365
412
  """通道级后验查询:channel=None → 全量+分通道;channel=str → 单通道。"""
366
413
  hist = channel_history(cg, limit=limit)
@@ -375,23 +422,35 @@ def channel_posterior(cg, channel=None, limit=HIT_HISTORY_MAX):
375
422
  for ch, hits in sorted(hist.items())}}
376
423
 
377
424
 
425
+ # 生效条件:传入 cg 与 route 时,trend 取 route 的 confidence、boundary 取 _boundary_consistency(cg, route['path'])、verification 缺省时取 hit_rate(cg)、balance 取 _branch_diversity(route),并按 W_TREND/W_BOUNDARY/W_VERIFICATION/W_BALANCE 加权返回 composite;仅当 W_META>0(PREDICTION_META_DIM 显式启用第五维)时才额外取 d_meta.pressure(d_meta.compute(cg), META_PROXY) 作第五维、落 meta_pressure 键、把 W_META*meta_pressure 计入 composite,关闭时返回键集合与 composite 逐字节不变;
378
426
  def score_route(cg, route, verification=None):
379
- """D-004 T_pred 四维评分(verification 跨路线共享,来自命中率)。"""
427
+ """D-004 T_pred 四维评分 + **D_meta 第五维(opt-in)**。
428
+
429
+ `verification` 跨路线共享(来自命中率)。第五维 `meta_pressure` 取
430
+ **单一指定代理**(`PREDICTION_META_PROXY`,缺省 `unmodeled_growth`)——
431
+ **不做三代理加权合成**(智能论3.4 §2.7.0 DEV-002a)。默认权重 0:
432
+ 不落键、不改 composite、SORT_KEYS 不扩张(默认零变更纪律)。
433
+ """
380
434
  trend = float(route.get("confidence") or 0.0)
381
435
  boundary = _boundary_consistency(cg, route.get("path") or [])
382
436
  ver = float(verification if verification is not None else hit_rate(cg))
383
437
  balance = _branch_diversity(route)
384
438
  composite = (W_TREND * trend + W_BOUNDARY * boundary
385
439
  + W_VERIFICATION * ver + W_BALANCE * balance)
386
- return {"trend": round(trend, 4), "boundary": boundary,
387
- "verification": round(ver, 4), "balance": balance,
388
- "composite": round(composite, 4),
389
- "weights": {"trend": W_TREND, "boundary": W_BOUNDARY,
390
- "verification": W_VERIFICATION, "balance": W_BALANCE}}
440
+ out = {"trend": round(trend, 4), "boundary": boundary,
441
+ "verification": round(ver, 4), "balance": balance,
442
+ "composite": round(composite, 4), "weights": _weights()}
443
+ if W_META > 0: # 第五维 opt-in:默认不落键
444
+ from . import d_meta # 惰性导入:叶子只读模块,防循环
445
+ mp = d_meta.pressure(d_meta.compute(cg), META_PROXY)
446
+ out["meta_pressure"] = mp
447
+ out["composite"] = round(composite + W_META * mp, 4)
448
+ return out
391
449
 
392
450
 
393
451
  # ---------------------------------------------------------------- 盲区驱动
394
452
 
453
+ # 生效条件:blindspot_id 去空后非空且能取到盲区报表时,匹配 unresolved 的 node_id 返回 kind='unresolved',否则匹配 items 的 query 或其 _key 相等返回 kind='blindspot_cluster',均未命中或取报表抛异常返回 None;
395
454
  def find_blindspot(cg, blindspot_id):
396
455
  """按 id 定位盲区:unresolved 节点优先,其次盲区邻域(按 query 键)。"""
397
456
  from . import metacognition
@@ -415,6 +474,7 @@ def find_blindspot(cg, blindspot_id):
415
474
  return None
416
475
 
417
476
 
477
+ # 生效条件:blindspot 的 description 中匹配到「可预测性:X」时返回 X 去除空白并小写,未匹配则返回 'predictable';
418
478
  def predictability(blindspot):
419
479
  """可预测性:盲区可显式声明 `# 可预测性:unknowable`。
420
480
 
@@ -425,13 +485,22 @@ def predictability(blindspot):
425
485
  return m.group(1).strip().lower() if m else "predictable"
426
486
 
427
487
 
488
+ # 生效条件:description 去空后非空时以 cg.search 取常量 ANCHOR_FETCH_K 个候选,跳过 layer 属常量 ANCHOR_SKIP_LAYERS 或 tags 命中常量 ANCHOR_SKIP_TAGS 者,返回首个出边非空的合格节点 id,否则降级返回首个合格候选 id;description 为空、检索抛异常或候选全被过滤返回 None;
428
489
  def anchor_from_description(cg, description):
429
490
  """盲区描述 → 锚点节点(检索器打分,与 AEIS 的 LIKE→坐标回退同构)。
430
491
 
431
- 只取**首个可用候选**:按标签/层过滤掉推断脚手架(`gap_hint`/`scene`)与
432
- 负记忆(`unresolved`/`rejected`),其余按检索名次顺延。过滤理由见上方常量注释。
433
- 候选全被过滤时返回 None(等价「无锚点」),由调用方按 no_anchor 处理,
434
- 而不是硬凑一个不可起推的节点。
492
+ 择锚规则:候选池内**可起推者优先**——出边非空是路线生成的必要条件,无出边的
493
+ 节点只能靠语义回退硬凑路线,起点语义即失真。**全部不可起推时才降级**为首个合格
494
+ 候选(诚实降级:宁可标注锚点弱,不假装有锚)。
495
+ 动机(实测):同分并列时检索序不可依赖——「正题节点」与其「同名+近义描述」变体
496
+ 词法分可完全相同(各自都为 1.0),纯按检索名次取首位会漂到无出边的近义变体上。
497
+
498
+ 过滤与择锚分两关:先按标签/层过滤掉推断脚手架(`gap_hint`/`scene`)与负记忆
499
+ (`unresolved`/`rejected`),再在剩余候选里按**可起推资格**择优——出边非空者
500
+ 立即采纳,无出边者记为降级候选继续后看,全池无可起推者才降级取首个合格候选。
501
+ 候选全被过滤时返回 None(等价「无锚点」),由调用方按 no_anchor 处理。
502
+ 邻接表不可用(chain 取表异常)时退回「取首个合格候选」——辅助判据故障不应
503
+ 让整条预测链失效(兜底优先于择优)。
435
504
  """
436
505
  q = str(description or "").strip()
437
506
  if not q:
@@ -440,6 +509,12 @@ def anchor_from_description(cg, description):
440
509
  results, _meta = cg.search(q, k=ANCHOR_FETCH_K, record=False, judge=False)
441
510
  except Exception:
442
511
  return None
512
+ try:
513
+ from . import chain
514
+ out_edges = chain.adjacency(cg)
515
+ except Exception:
516
+ out_edges = None
517
+ fallback = None
443
518
  for item in results:
444
519
  nd = item[0] if isinstance(item, (tuple, list)) else item
445
520
  if not isinstance(nd, dict):
@@ -459,12 +534,17 @@ def anchor_from_description(cg, description):
459
534
  # 兜底:fs 派生的 id 可能是相对路径(如 unresolved/bs_x.md),归一为裸节点名
460
535
  if "/" in str(nid) and str(nid).endswith(".md"):
461
536
  nid = os.path.basename(str(nid))[:-3]
462
- return nid
463
- return None
537
+ # 可起推资格:出边非空是路线生成的必要条件;不可起推者只作降级候选。
538
+ if out_edges is None or out_edges.get(nid):
539
+ return nid
540
+ if fallback is None:
541
+ fallback = nid
542
+ return fallback
464
543
 
465
544
 
466
545
  # ---------------------------------------------------------------- 路线生成
467
546
 
547
+ # 生效条件:cg.get(nid) 的 content 含非空行时返回首行去掉开头 '#' 后的前 60 字符,否则返回 nid;
468
548
  def _label(cg, nid):
469
549
  node = cg.get(nid) or {}
470
550
  for line in (node.get("content") or "").splitlines():
@@ -474,6 +554,7 @@ def _label(cg, nid):
474
554
  return nid
475
555
 
476
556
 
557
+ # 生效条件:start_id 去空后非空且存在于 _nodes(cg) 时,horizon 裁剪到 [1, HORIZON_HARD]、max_branches 裁剪到 [1, MAX_BRANCHES_HARD] 后 DFS,返回 status='ok' 及带 uncertainty_bound/extrapolation_validity/score/path_labels 的 routes;start_id 为空或不在节点集中返回 status='start_not_found';
477
558
  def _generate(cg, start_id, horizon, max_branches, semantic=True):
478
559
  """D-001 局部路径 DFS 生成候选未来(差异 3:增加 path 防环)。"""
479
560
  start_id = str(start_id or "").strip()
@@ -485,6 +566,7 @@ def _generate(cg, start_id, horizon, max_branches, semantic=True):
485
566
  ver = hit_rate(cg)
486
567
  out = []
487
568
 
569
+ # 生效条件:当 depth < horizon(enclosing 上界)时,对 branch_candidates(cg, cur, semantic=semantic) 取前 max_branches 个候选展开——候选 node_id 已在 path 中则 continue 跳过,否则把 cand["confidence"] 连乘(初始 1.0,结果 round 4)连同 conds/sources/relations 各自追加 cand 对应字段后作为一条路径写入外层 out,并以该 node_id、depth+1 递归;depth >= horizon 时直接返回且不产生任何路径。
488
570
  def dfs(cur, path, confs, conds, sources, relations, depth):
489
571
  if depth >= horizon:
490
572
  return
@@ -520,6 +602,7 @@ def _generate(cg, start_id, horizon, max_branches, semantic=True):
520
602
  "generated_at": time.time()}}
521
603
 
522
604
 
605
+ # 生效条件:传入 cg、res、sort、limit 时,sort 不属于常量 SORT_KEYS 则退回 'composite',按该键排序并在 limit 为正时截断,追加一条 type 为 log_type(默认 'predict_routes')的留痕后返回 res;
523
606
  def _finalize(cg, res, sort, limit, log_type="predict_routes"):
524
607
  """排序 / 限流 / 留痕(预测本身可审计)。"""
525
608
  if sort not in SORT_KEYS:
@@ -538,6 +621,7 @@ def _finalize(cg, res, sort, limit, log_type="predict_routes"):
538
621
  return res
539
622
 
540
623
 
624
+ # 生效条件:blindspot_id 非空时转交 routes_from_blindspot;否则 start_id 为空返回 status='no_start',_generate 返回非 ok 则原样返回,ok 则经 _finalize(cg, res, sort, limit) 返回;
541
625
  def routes(cg, start_id=None, blindspot_id=None, horizon=HORIZON_DEFAULT,
542
626
  max_branches=MAX_BRANCHES_DEFAULT, sort="composite", limit=0,
543
627
  semantic=True):
@@ -562,6 +646,7 @@ def routes(cg, start_id=None, blindspot_id=None, horizon=HORIZON_DEFAULT,
562
646
  return _finalize(cg, res, sort, limit)
563
647
 
564
648
 
649
+ # 生效条件:find_blindspot 得 None 时返回 status='blindspot_not_found',其 predictability 为 'unknowable' 时返回 status='unpredictable',anchor_from_description 无锚点时返回 status='no_anchor',有锚点则以其 _generate 并在 ok 时经 _finalize(log_type='predict_routes_blindspot')返回;
565
650
  def routes_from_blindspot(cg, blindspot_id, horizon=HORIZON_DEFAULT,
566
651
  max_branches=MAX_BRANCHES_DEFAULT, sort="composite",
567
652
  limit=0, semantic=True):
@@ -592,10 +677,12 @@ def routes_from_blindspot(cg, blindspot_id, horizon=HORIZON_DEFAULT,
592
677
  _SAFE_LAYERS = ("knowledge", "contextual", "structural")
593
678
 
594
679
 
680
+ # 生效条件:传入 edge 时返回其 'target'、'to'、'dst' 中首个非空值,三者皆空则返回 None;
595
681
  def _edge_target(edge):
596
682
  return edge.get("target") or edge.get("to") or edge.get("dst")
597
683
 
598
684
 
685
+ # 生效条件:传入 cg 与 node_id 时,仅当存在指向 node_id 的因果/时序边且其源节点 frontmatter 的 layer 属于常量 _SAFE_LAYERS,才把该边 confidence 提升 min(1.0, 原值+delta)(delta 默认常量 EDGE_BOOST)并回写,返回被改源节点列表,无满足者返回空列表;
599
686
  def _boost_incoming(cg, node_id, delta=EDGE_BOOST, actor="predict"):
600
687
  """命中 → 指向该节点的因果/时序边置信度 +delta。
601
688
 
@@ -652,6 +739,7 @@ def _boost_incoming(cg, node_id, delta=EDGE_BOOST, actor="predict"):
652
739
  return changed
653
740
 
654
741
 
742
+ # 生效条件:传入 cg 时若 _hit_history(cg, limit) 样本数少于常量 MIN_SAMPLES,返回 threshold 为常量 BASE_HIT_RATE 且 reflect=False;样本足够则以 max(BASE_HIT_RATE, mean-2σ) 为 threshold,命中均值低于该值时 reflect=True;
655
743
  def dynamic_hit_threshold(cg, limit=HIT_HISTORY_MAX):
656
744
  """D-006 命中率动态校准(2.7.2 动态死区)。
657
745
 
@@ -675,6 +763,7 @@ def dynamic_hit_threshold(cg, limit=HIT_HISTORY_MAX):
675
763
  else "命中率正常"}
676
764
 
677
765
 
766
+ # 生效条件:cg 与 predicted_node_id 给出即执行——predicted_node_id 为假值(None/0/"")时 pred 取空串,actual_node_id 为假值时 act 回落为 pred,hit 为 None 时按 pred==act 判定;hit 为真时 out["boosted"] 取 _boost_incoming(cg, act, EDGE_BOOST, actor=actor),hit 为假时 out["rejected_id"] 取 cg.add_rejected(...)(该调用抛异常时改记 out["rejected_error"]),随后 out 合并 dynamic_hit_threshold(cg),sync_self 为真时导入 self_state.refresh(cg, actor=actor) 写 out["self_state"](抛异常时写 out["self_state_error"]),返回 out。
678
767
  def feedback(cg, predicted_node_id, actual_node_id=None, hit=None, note="",
679
768
  actor="predict", sync_self=True, channel=None):
680
769
  """预测反馈(D-006):hit → 边置信度 +0.05;miss → 登记 rejected。
@@ -725,10 +814,12 @@ LEARN_LOG = "_learn.jsonl"
725
814
  LEARN_MAX_STEPS = 8
726
815
 
727
816
 
817
+ # 生效条件:传入 cg 具 root 属性时返回 root 与模块级常量 LEARN_LOG 的路径拼接,缺 root 则以 '.' 拼接;
728
818
  def learn_log_path(cg):
729
819
  return os.path.join(getattr(cg, "root", "."), LEARN_LOG)
730
820
 
731
821
 
822
+ # 生效条件:传入 cg 与 rec 时向 learn_log_path(cg) 追加一条 JSONL 记录,任何异常被吞掉且无返回值;
732
823
  def _learn_append(cg, rec):
733
824
  try:
734
825
  append_jsonl(learn_log_path(cg), rec)
@@ -736,6 +827,7 @@ def _learn_append(cg, rec):
736
827
  pass
737
828
 
738
829
 
830
+ # 生效条件:nid 去空后非空、cg.get(nid) 的 frontmatter layer 等于 'knowledge' 且其 content 含常量 consolidate.CCG_REQUIRED 全部要素行时返回 True,否则返回 False;
739
831
  def _is_settled(cg, nid):
740
832
  """终点是否已达「可判定」态:知识层 ∧ CCG 五要素齐全。"""
741
833
  nid = str(nid or "").strip()
@@ -757,11 +849,13 @@ def _is_settled(cg, nid):
757
849
  return False
758
850
 
759
851
 
852
+ # 生效条件:传入 route 且其 'path' 非空时返回路径最后一个节点 id,路径为空或 route 为 None 时返回 None;
760
853
  def _terminal_node(route):
761
854
  path = list((route or {}).get("path") or [])
762
855
  return path[-1] if path else None
763
856
 
764
857
 
858
+ # 生效条件:传入 cg、bid、step、actor 时,cg 中不存在由 bid 的 sha1 派生的 gap 节点 id 则写入 contextual 的 gap_hint 节点并返回该 id;该 id 已存在或 cg.add 抛异常时返回 None;
765
859
  def _write_gap(cg, bid, step, actor):
766
860
  """把待补线索写成 contextual 的 ``gap_hint`` 节点(幂等,非事实断言)。"""
767
861
  nid = "gap_%s" % hashlib.sha1(bid.encode("utf-8")).hexdigest()[:10]
@@ -787,6 +881,7 @@ def _write_gap(cg, bid, step, actor):
787
881
  return None
788
882
 
789
883
 
884
+ # 生效条件:blindspot_id 给出但 find_blindspot 找不到时返回 ok=False 与 status='not_found';否则逐条按 unknowable/no_anchor/unresolved/carried/resolved 判定,apply 为真且 cg 可写时才把 carried/unresolved 落成幂等 gap_hint 节点;
790
885
  def learn_blindspots(cg, blindspot_id=None, limit=LEARN_MAX_STEPS,
791
886
  horizon=HORIZON_DEFAULT, max_branches=MAX_BRANCHES_DEFAULT,
792
887
  apply=False, actor="insight", **extra):
@@ -885,6 +980,7 @@ def learn_blindspots(cg, blindspot_id=None, limit=LEARN_MAX_STEPS,
885
980
  "resolved 仅表示已有可判定终点,未改动任何事实层节点")}
886
981
 
887
982
 
983
+ # 生效条件:传入 cg 时基于 _read_log(cg) 统计 type 以 'predict_routes' 开头的调用数与 n_routes 合计、feedback 样本与命中率(无样本取常量 BASE_HIT_RATE),并附 channel_posterior 与 dynamic_hit_threshold,recent 取末尾 limit 条(limit 默认 20,为 0 时为空);
888
984
  def stats(cg, limit=20):
889
985
  """预测统计:调用数、生成路线数、反馈样本、命中率、动态阈值。"""
890
986
  recs = _read_log(cg)
@@ -903,6 +999,7 @@ def stats(cg, limit=20):
903
999
 
904
1000
  # ---------------------------------------------------------------- 因果推理
905
1001
 
1002
+ # 生效条件:传入 cg 与 path 且 path 长度不少于 2 时,对每对相邻节点返回其在邻接表中且关系类型属于常量 CAUSAL_BRANCH_TYPES 的边条件(无匹配则为空串)逐跳列表,path 更短则返回空列表;
906
1003
  def _path_conditions(cg, path):
907
1004
  """路径上每跳的边条件(与节点对一一对应)。"""
908
1005
  from . import chain
@@ -919,6 +1016,7 @@ def _path_conditions(cg, path):
919
1016
  return conds
920
1017
 
921
1018
 
1019
+ # 生效条件:a_id 或 b_id 去空后为空时返回 ok=False 与 error='missing_node';a_id 等于 b_id 返回可达且长度 0;否则仅在常量 CAUSAL_BRANCH_TYPES 边上于 max_depth(下限 1)内 BFS,可达返回路径与逐跳 conditions,不可达返回 reachable=False;
922
1020
  def causal_path(cg, a_id, b_id, max_depth=5):
923
1021
  """因果路径推理:A 能否沿因果/时序边到达 B(BFS,最短路径)。
924
1022
 
@@ -962,6 +1060,7 @@ def causal_path(cg, a_id, b_id, max_depth=5):
962
1060
 
963
1061
  # ---------------------------------------------------------------- 自描述
964
1062
 
1063
+ # 生效条件:不适用(无必需形参与模块级常量)
965
1064
  def catalog():
966
1065
  """决策编号 / 权重 / 校准参数 / 与 AEIS 的差异(供协议对照验证)。"""
967
1066
  return {
@@ -980,8 +1079,7 @@ def catalog():
980
1079
  "P-T-73/74": "通道贝叶斯后验(Beta-Bernoulli,置信度≠可信度;"
981
1080
  "feedback channel 参数 + channel_posterior 查询)",
982
1081
  },
983
- "weights": {"trend": W_TREND, "boundary": W_BOUNDARY,
984
- "verification": W_VERIFICATION, "balance": W_BALANCE},
1082
+ "weights": _weights(), # 第五维 opt-in 时同步扩张(防文档漂移)
985
1083
  "calibration": {"min_samples": MIN_SAMPLES,
986
1084
  "base_hit_rate": BASE_HIT_RATE,
987
1085
  "edge_boost": EDGE_BOOST,
@@ -1000,4 +1098,4 @@ def catalog():
1000
1098
  ],
1001
1099
  "actions": ["routes", "routes_from_blindspot", "feedback", "stats",
1002
1100
  "causal_path", "causal_gate", "catalog"],
1003
- }
1101
+ }
@@ -44,6 +44,7 @@ from __future__ import annotations
44
44
  MIN_DISCRIM = 0.1
45
45
 
46
46
 
47
+ # 生效条件:atoms 经 `a for a in (atoms or ()) if a` 过滤后为空(atoms 为 None/空容器/元素全为假值)→ 返回 [],否则取过滤后前 n 项,n = max(1, int(len(toks)*ratio)),故 ratio=0 或负值时仍返回 1 项、ratio=1.0 时返回全部。
47
48
  def core_subset(atoms, ratio=0.5):
48
49
  """Stage-1 宽检索核心子集:归一序列前 int(len*ratio) 个(保序,确定性)。
49
50
 
@@ -57,6 +58,7 @@ def core_subset(atoms, ratio=0.5):
57
58
  return toks[:n]
58
59
 
59
60
 
61
+ # 生效条件:cand_sets 长度 < 2 或 unused 为假值/空序列 → 返回 None;否则对 unused 保序逐项算 cov=命中 cand_sets 的比例、gap=1-|2*cov-1|,返回 gap 严格大于 float(min_gap)(默认模块常量 MIN_DISCRIM)者中 gap 最大者,同 gap 取 unused 原序靠前者;无满足者返回 None。
60
62
  def discriminative(unused, cand_sets, min_gap=MIN_DISCRIM):
61
63
  """候选间区分度最大的未用原子(确定性:同 gap 取归一序列原序靠前者)。
62
64
 
@@ -76,6 +78,7 @@ def discriminative(unused, cand_sets, min_gap=MIN_DISCRIM):
76
78
  return best
77
79
 
78
80
 
81
+ # 生效条件:atoms 真值过滤后为空 → 返回 {'stages': [], 'added': [], 'converged': False};否则从 used=core_subset(toks, ratio) 起在 range(max_stages) 内循环,每阶段记录 rank_fn(used) 的前 k(默认 10)个 cid 与当前 used,若 stage==max_stages-1 则 break 且 converged 保持 False,非末阶段则用 pool(cond_pool 为真值时取 list(cond_pool),否则回落为 toks 真值过滤后的 atoms)中未用原子对 top 的 cand_atoms.get(cid, frozenset()) 调 discriminative:结果非 None 时并入 used 并追加进 added 继续循环,为 None 时置 converged=True 提前结束。
79
82
  def progressive_search(rank_fn, atoms, cand_atoms,
80
83
  ratio=0.5, k=10, max_stages=4,
81
84
  cond_pool=None, min_gap=MIN_DISCRIM):
package/md_cg/protect.py CHANGED
@@ -3,14 +3,14 @@
3
3
 
4
4
  理论出处(全部来自本仓已有文档,非外部发明):
5
5
 
6
- · `docs/灵枢_自我层定义.md:6`
6
+ · `docs/mdcg/灵枢_自我层定义.md:6`
7
7
  SELF 层 = 身份 + 价值观 + 图接口,**不可遗忘**、跨会话自动加载。
8
8
  任何实例都能改写自我层 = 自我认知可被任意覆写,与「自我」定义冲突。
9
- · `docs/认知图_MD目录方案_v0.1.md:53`
9
+ · `docs/mdcg/认知图_MD目录方案_v0.1.md:53`
10
10
  `anchor/ # 锚点层(不可遗忘,保护)`
11
- · `docs/认知图_MD目录方案_v0.1.md:412-416`
11
+ · `docs/mdcg/认知图_MD目录方案_v0.1.md:412-416`
12
12
  「importance 提升(保护:不可遗忘记入 anchor/ 且**受保护标记**)」
13
- · `docs/tool_table_v0.3.0.md:15`
13
+ · `docs/mdcg/tool_table_v0.3.0.md:15`
14
14
  「importance_hint 可显式提示重要性(**≥0.7 触发不可遗忘保护**)」
15
15
 
16
16
  三层保护(任一命中即受保护):
@@ -53,10 +53,12 @@ class ProtectionError(PermissionError):
53
53
 
54
54
  # ---------------------------------------------------------------- 判定
55
55
 
56
+ # 生效条件:对任意 cg、node_id 无条件返回 `(cg.index 或其假值时的 {})["nodes"]`(该键缺失或假值时为 `{}`)中以 node_id 为键的值,索引无此键时返回 None。
56
57
  def _entry(cg, node_id):
57
58
  return ((getattr(cg, "index", None) or {}).get("nodes") or {}).get(node_id)
58
59
 
59
60
 
61
+ # 生效条件:cg 索引中无 node_id 条目时返回 None;有条目时先取 layer/importance(缺 importance 键回落 0.5)/protected/protection_reason/immutable/self_state,仅当条目缺 protected 或 immutable、或(缺 self_state 且条目 layer∈PROTECTED_LAYERS)时再经 cg.get(node_id) 用 frontmatter 覆盖这四个键(cg.get 抛异常或返回假值时保留索引值;layer 取 frontmatter.layer or 索引 layer,importance 缺键时回落索引 importance)。
60
62
  def _fm(cg, node_id):
61
63
  """取判定所需的 frontmatter 字段;索引快照缺 protected 时回退读文件。"""
62
64
  e = _entry(cg, node_id)
@@ -91,6 +93,7 @@ def _fm(cg, node_id):
91
93
  return fm
92
94
 
93
95
 
96
+ # 生效条件:cg 索引无 node_id 条目(_fm 直接返回 None,不走回退读文件)时返回 (False, '');有条目时按 layer∈PROTECTED_LAYERS 返回 (True, 层保护);否则 protected is True 时返回 (True, protection_reason 或 '显式保护标记');否则 importance(缺失/假值/float 转换异常一律按 0.0)≥AUTO_PROTECT_IMPORTANCE 时返回 (True, 重要性保护);其余返回 (False, '')。
94
97
  def is_protected(cg, node_id):
95
98
  """**不可遗忘**判定 → (是否受保护, 原因)。节点不存在返回 (False, "")。"""
96
99
  fm = _fm(cg, node_id)
@@ -110,6 +113,7 @@ def is_protected(cg, node_id):
110
113
  return False, ""
111
114
 
112
115
 
116
+ # 生效条件:cg 索引无 node_id 条目时返回 (False, '');有条目时若 self_state is True 一律返回 (False, '')(自我状态豁免);否则 layer∈PROTECTED_LAYERS 返回 (True, 层保护);否则 immutable is True 返回 (True, protection_reason 或 '显式不可覆盖标记');其余返回 (False, '')。
113
117
  def is_immutable(cg, node_id):
114
118
  """**不可覆盖**判定 → (是否不可篡改, 原因)。比不可遗忘更窄,只认强信号。
115
119
 
@@ -133,6 +137,7 @@ def is_immutable(cg, node_id):
133
137
 
134
138
  # ---------------------------------------------------------------- 留痕
135
139
 
140
+ # 生效条件:对任意 cg、action、node_id、reason(actor/snapshot 缺省为 None)都构造含 t/action/node_id/reason/actor/snapshot 的 rec 并返回,同时尝试追加写入 cg.root 下的 AUDIT_FILE,该写入抛出的任何异常被吞掉且不影响返回值。
136
141
  def _audit(cg, action, node_id, reason, actor=None, snapshot=None):
137
142
  rec = {"t": time.time(), "action": action, "node_id": node_id,
138
143
  "reason": reason, "actor": actor, "snapshot": snapshot}
@@ -143,6 +148,7 @@ def _audit(cg, action, node_id, reason, actor=None, snapshot=None):
143
148
  return rec
144
149
 
145
150
 
151
+ # 生效条件:cg.get(node_id) 抛异常或返回假值时返回 None;否则在 cg.root/HISTORY_DIR/node_id 下以时间戳命名写入当前 frontmatter 与 content,_write_node 抛异常时返回 None,成功则返回相对 cg.root 且以 '/' 分隔的路径。
146
152
  def snapshot(cg, node_id):
147
153
  """把节点当前版本快照进 `_protected_history/<id>/<ts>.md`,返回相对路径。"""
148
154
  try:
@@ -163,6 +169,7 @@ def snapshot(cg, node_id):
163
169
  return os.path.relpath(p, cg.root).replace("\\", "/")
164
170
 
165
171
 
172
+ # 生效条件:cg.root/HISTORY_DIR/node_id 不是目录时返回 [];是目录时返回该目录下以 .md 结尾(不递归)的文件按名称排序后的 `HISTORY_DIR/node_id/文件名` 列表,无匹配文件则列表为空。
166
173
  def history(cg, node_id):
167
174
  """受保护节点的历史版本列表(按时间升序)。"""
168
175
  d = os.path.join(cg.root, HISTORY_DIR, node_id)
@@ -175,12 +182,14 @@ def history(cg, node_id):
175
182
 
176
183
  # ---------------------------------------------------------------- 守卫
177
184
 
185
+ # 生效条件:对任意 cg、node_id、why、action、override、actor 都无条件返回 {'override': True, 'reason': why, 'snapshot': snapshot(...) 的结果, 'audit': _audit(cg, action, node_id, why, actor, snap) 的结果},override 形参本身不改变返回内容。
178
186
  def _allow(cg, node_id, why, action, override, actor):
179
187
  snap = snapshot(cg, node_id)
180
188
  rec = _audit(cg, action, node_id, why, actor, snap)
181
189
  return {"override": True, "reason": why, "snapshot": snap, "audit": rec}
182
190
 
183
191
 
192
+ # 生效条件:is_immutable(cg, node_id) 为假(含 self_state is True、layer 不在 PROTECTED_LAYERS 且 immutable 非 True 的情形)时返回 None;为真时 override 取真值则返回 _allow(..., 'override_write', override, actor),否则抛出 ProtectionError;layer 形参不参与该判定。
184
193
  def guard_write(cg, node_id, layer=None, override=False, actor=None):
185
194
  """覆盖既有节点前的守卫(只认**不可覆盖**信号)。
186
195
 
@@ -196,6 +205,7 @@ def guard_write(cg, node_id, layer=None, override=False, actor=None):
196
205
  f"节点 {node_id} 受写保护({why});覆盖需显式 override=True")
197
206
 
198
207
 
208
+ # 生效条件:is_protected(cg, node_id) 为假时返回 None;为真时 override 取真值则返回 _allow(..., 'override_forget', override, actor),否则抛出 ProtectionError。
199
209
  def guard_forget(cg, node_id, override=False, actor=None):
200
210
  """删除前的守卫。受保护节点 = 不可遗忘。"""
201
211
  prot, why = is_protected(cg, node_id)
@@ -207,6 +217,7 @@ def guard_forget(cg, node_id, override=False, actor=None):
207
217
  f"节点 {node_id} 不可遗忘({why});删除需显式 override=True")
208
218
 
209
219
 
220
+ # 生效条件:is_protected(cg, node_id) 为假时返回 None;为真且 to_layer∈PROTECTED_LAYERS(保护层间互搬)时也返回 None;为真且 to_layer 不在 PROTECTED_LAYERS 时,override 取真值则返回 _allow(..., 'override_move', override, actor),否则抛出 ProtectionError。
210
221
  def guard_move(cg, node_id, to_layer, override=False, actor=None):
211
222
  """降级/搬迁前的守卫:受保护节点不得被移出保护层。"""
212
223
  prot, why = is_protected(cg, node_id)
@@ -220,6 +231,7 @@ def guard_move(cg, node_id, to_layer, override=False, actor=None):
220
231
  f"节点 {node_id} 受写保护({why});降级移出保护层需显式 override=True")
221
232
 
222
233
 
234
+ # 生效条件:cg.get(node_id) 抛异常或返回假值时返回 None;否则把 protected=True 与 protection_reason=reason 写入 cg.root 下 node["path"](该键缺失即抛 KeyError)对应的 frontmatter 并保持原 content,随后门条目存在时同步其 protected/protection_reason,返回 {'node_id': node_id, 'protected': True, 'reason': reason}。
223
235
  def mark(cg, node_id, reason):
224
236
  """给节点打上 `protected=True` 标记(写回 frontmatter,不动 content)。"""
225
237
  try:
@@ -240,6 +252,7 @@ def mark(cg, node_id, reason):
240
252
  return {"node_id": node_id, "protected": True, "reason": reason}
241
253
 
242
254
 
255
+ # 生效条件:遍历 cg.index.nodes(或其假值时的空字典)的每个键,对 is_protected 为真的节点计入 ids 并按 layer(缺失/假值记为 '?')累加 by_layer,其中原因串含 "importance=" 或以 "重要性保护" 开头的计入 auto_by_importance,对 is_immutable 为真的计入 immutable_ids,返回含 protected_count/immutable_count/by_layer/auto_by_importance/ids/immutable_ids 的字典。
243
256
  def stats(cg):
244
257
  """保护面盘点:不可遗忘数 / 不可覆盖数 / 分层分布 / 自动保护命中数。"""
245
258
  nodes = ((getattr(cg, "index", None) or {}).get("nodes") or {})
@@ -257,4 +270,4 @@ def stats(cg):
257
270
  immutable.append(nid)
258
271
  return {"protected_count": len(ids), "immutable_count": len(immutable),
259
272
  "by_layer": by_layer, "auto_by_importance": auto, "ids": ids,
260
- "immutable_ids": immutable}
273
+ "immutable_ids": immutable}