@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
@@ -0,0 +1,203 @@
1
+ # -*- coding: utf-8 -*-
2
+ """test_action_derive · action 缺省静默降级防呆(与 op 推导同构)
3
+
4
+ 背景:`op` 传了、`action` 漏了 → 各分支按字面量默认 action 执行。若默认恰是
5
+ 读类(list / routes / stat / outlook / ping),写意图会被**静默吞掉**且返回
6
+ 形似正常的结果。最典型是文档化契约 `cg(op=review, pid, decision, reason)`
7
+ (不带 action,见 docs/mdcg/主代理子代理记忆架构设计.md)实际静默走
8
+ review_list —— 裁决从未落盘,属契约与实现漂移。
9
+
10
+ 修复(md_cg/mcp_server.py `_ACTION_SIGS` / `_action_sig` / `_cg_call`):
11
+ ① 签名明确指向非默认 action → 按签名推导并补进 args(不再被默认吞掉);
12
+ ② 无签名可依 → 维持默认执行,但透出 action_derived + hint_action(不再静默);
13
+ ③ 判据用「键存在且非 None」——False / 0 / "" 属显式传入,避免真值判断误吞;
14
+ ④ `_ACTION_DEFAULT` 是「分支缺省 action 字面量」的唯一登记表,本测试含
15
+ **同源守卫**(表 ↔ 源码双向比对),防表与实现漂移。
16
+
17
+ 边界:action 仍是可选参数;推导只在「缺 action 且签名明确」时生效,显式传
18
+ action 的行为逐位不变;`ingest` 的 path→类型推导取**保守优先**(file 最保守:
19
+ 若实为目录会报错可见,而不会误把整棵目录树摄进来)。
20
+ """
21
+ import os
22
+ import re
23
+ import sys
24
+ import tempfile
25
+
26
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
27
+
28
+ # Windows cmd 默认 GBK:带圈数字等非 GBK 字符打印即 UnicodeEncodeError,且崩在
29
+ # 断言之后、报告之前 —— 同一测试「因环境而异」。自带 UTF-8 兜底。
30
+ if hasattr(sys.stdout, "reconfigure"):
31
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
32
+
33
+ from md_cg import mcp_server as M
34
+ from md_cg.mdcos import MdCGSecure
35
+ from md_cg.security import DEFAULT_SENSITIVITY, Principal
36
+
37
+ _ok = 0
38
+ _fail = []
39
+
40
+
41
+ def check(name, cond, detail=""):
42
+ global _ok
43
+ if cond:
44
+ _ok += 1
45
+ print("[PASS] " + name)
46
+ else:
47
+ _fail.append(name)
48
+ print("[FAIL] %s · %s" % (name, str(detail)[:240]))
49
+
50
+
51
+ def _p(actor="tester", session="sess_a"):
52
+ return Principal(actor=actor, clearance=DEFAULT_SENSITIVITY,
53
+ can_write=True, can_admin=True, role="designer",
54
+ session=session, harness="test-harness")
55
+
56
+
57
+ def _raises(fn):
58
+ try:
59
+ fn()
60
+ return None
61
+ except Exception as e: # noqa: BLE001
62
+ return e
63
+
64
+
65
+ # ==================== A. 纯函数:签名推导 ====================
66
+ SIG = M._action_sig
67
+
68
+ check("A1 review+decision→decide(契约漂移核心)",
69
+ SIG({"decision": "accept"}, "review") == ("decide", "decision"))
70
+ check("A2 review+node_id→verify_record",
71
+ SIG({"node_id": "n1"}, "review") == ("verify_record", "node_id"))
72
+ check("A3 review 仅 pid 不猜(保持 list,避免误判 rounds/records)",
73
+ SIG({"pid": "p1"}, "review") == (None, None))
74
+ check("A4 recent+text→add", SIG({"text": "hi"}, "recent") == ("add", "text"))
75
+ check("A4b recent+content→add",
76
+ SIG({"content": "hi"}, "recent") == ("add", "content"))
77
+ check("A5 goal+goal→add", SIG({"goal": "G"}, "goal") == ("add", "goal"))
78
+ check("A6 predict+hit=False 仍推导(键存在即签名,非真值判断)",
79
+ SIG({"hit": False}, "predict") == ("feedback", "hit"))
80
+ check("A7 predict 空参数→不猜", SIG({}, "predict") == (None, None))
81
+ check("A8 session+summary→note",
82
+ SIG({"summary": "s"}, "session") == ("note", "summary"))
83
+ check("A9 insight+statement→record",
84
+ SIG({"statement": "x"}, "insight") == ("record", "statement"))
85
+ check("A10 whitebox+question→ask",
86
+ SIG({"question": "q"}, "whitebox") == ("ask", "question"))
87
+ check("A10b whitebox+questions→verify_existing",
88
+ SIG({"questions": ["q"]}, "whitebox") == ("verify_existing", "questions"))
89
+ check("A11 ingest+*.jsonl→jsonl",
90
+ SIG({"path": "a/b.jsonl"}, "ingest") == ("jsonl", "path(*.jsonl)"))
91
+ check("A12 ingest+patterns→dir",
92
+ SIG({"path": "d", "patterns": ["*.md"]}, "ingest") == ("dir", "patterns"))
93
+ check("A13 ingest 裸 path→file(保守优先,不猜 dir)",
94
+ SIG({"path": "d"}, "ingest") == ("file", "path"))
95
+ check("A14 ingest 空 path→不猜", SIG({"path": " "}, "ingest") == (None, None))
96
+ check("A15 非推导 op 不猜", SIG({"decision": "accept"}, "link") == (None, None))
97
+ check("A16 显式 None 不算签名",
98
+ SIG({"decision": None, "node_id": "n1"}, "review") == ("verify_record", "node_id"))
99
+
100
+
101
+ # ==================== B. 同源守卫:表 ↔ 源码双向 ====================
102
+ _MCP_SRC = open(M.__file__, encoding="utf-8", errors="replace").read()
103
+ _WB_SRC = open(os.path.join(os.path.dirname(M.__file__), "whitebox.py"),
104
+ encoding="utf-8", errors="replace").read()
105
+ # 源码中所有 `a.get("action") or "<默认>"` 形式的缺省字面量
106
+ _pairs = set(re.findall(r'a\.get\("action"\)\s*or\s*"([a-z_]+)"', _MCP_SRC))
107
+ # ccg 的嵌套形态:`o.get("action") or a.get("action") or "<默认>"`
108
+ _oc = set(re.findall(r'o\.get\("action"\)\s*or\s+a\.get\("action"\)\s*or\s*"([a-z_]+)"',
109
+ _MCP_SRC))
110
+ _wb_pairs = set(re.findall(r'a\.get\("action"\)\s*or\s*"([a-z_]+)"', _WB_SRC))
111
+ _src_vals = _pairs | _oc | _wb_pairs
112
+ _table_vals = set(M._ACTION_DEFAULT.values())
113
+ check("B1 源码每个缺省 action 都在 _ACTION_DEFAULT 值域内(防漏列)",
114
+ _src_vals <= _table_vals, sorted(_src_vals - _table_vals))
115
+ check("B2 _ACTION_DEFAULT 每项都在源码中真实出现(防幻影表)",
116
+ _table_vals <= _src_vals, sorted(_table_vals - _src_vals))
117
+ check("B3 whitebox dispatch 的缺省 action=ping 真实存在(跨文件守卫)",
118
+ 'ping' in re.findall(r'a\.get\("action"\)\s*or\s*"([a-z_]+)"', _WB_SRC), _wb_pairs)
119
+ # 推导规则的目标 action 必须真实存在于对应分支识别面(抽样防幻影推导)
120
+ for _op, _acts in M._ACTION_SIGS.items():
121
+ _missing = [act for _, act in _acts
122
+ if ('"%s"' % act) not in _MCP_SRC and ('"%s"' % act) not in _WB_SRC]
123
+ check("B4 推导目标 action 在分支中被识别:%s" % _op, not _missing, _missing)
124
+
125
+
126
+ # ==================== C. 端到端:不再静默吞意图 ====================
127
+ root = tempfile.mkdtemp(prefix="mdcg_act_")
128
+ try:
129
+ cg = MdCGSecure(root, principal=_p())
130
+
131
+ # C1 review 契约漂移:带 decision 但不带 action(文档化契约形态)
132
+ out = M._cg_call(cg, {"op": "review", "pid": "no_such_pid",
133
+ "decision": "accept", "reason": "防呆测试"})
134
+ check("C1 review+decision 不再静默走 list(旧行为返回 pending)",
135
+ "pending" not in out, out)
136
+ check("C1b 确实进了 decide 分支(pid_not_found 属预期)",
137
+ out.get("error") == "pid_not_found", out)
138
+ check("C1c 透出 action_derived + hint_action",
139
+ out.get("action_derived") is True and bool(out.get("hint_action")), out)
140
+
141
+ # C2 全链路:真实提案 → 不传 action 裁决 accept → 必须真实落盘
142
+ pid = cg.propose("act_probe_1", "防呆测试候选内容(裁决真实落盘)",
143
+ layer="knowledge")
144
+ out2 = M._cg_call(cg, {"op": "review", "pid": pid, "decision": "accept",
145
+ "reason": "防呆测试:不带 action 的契约形态"})
146
+ check("C2 不带 action 的裁决真实落盘", out2.get("ok") is True, out2)
147
+ check("C2b 裁决后队列清空", len(cg.review_list()) == 0, cg.review_list())
148
+ got = cg.get("act_probe_1")
149
+ check("C2c 候选节点已按裁决写入", bool(got) and
150
+ "防呆测试候选内容" in (got.get("content") or ""), got)
151
+
152
+ # C3 recent + text 不再静默走 list(事件必须落盘)
153
+ out3 = M._cg_call(cg, {"op": "recent", "text": "防呆事件A"})
154
+ check("C3 recent+text 推导 add(旧行为返回 events 列表)",
155
+ "events" not in out3 and "event" in out3, out3)
156
+ _evs = cg.recent_events(limit=5)
157
+ check("C3b 事件确实写入近况窗口",
158
+ any("防呆事件A" in (e.get("text") or "") for e in _evs), _evs)
159
+ check("C3c 透出 action_derived", out3.get("action_derived") is True, out3)
160
+
161
+ # C4 goal + goal 不再静默走 list
162
+ out4 = M._cg_call(cg, {"op": "goal", "goal": "防呆目标G"})
163
+ check("C4 goal+goal 推导 add(旧行为返回 goals 列表)",
164
+ out4.get("ok") is True and bool(out4.get("id")), out4)
165
+ check("C4b 目标确实落盘",
166
+ any("防呆目标G" in (g.get("goal") or "") for g in cg.active_goals(limit=10)),
167
+ cg.active_goals(limit=10))
168
+
169
+ # C5 显式 action 零回归(推导不得覆盖显式意图)
170
+ out5 = M._cg_call(cg, {"op": "review", "action": "list"})
171
+ check("C5 显式 action=list 行为逐位不变",
172
+ "pending" in out5 and "action_derived" not in out5, out5)
173
+
174
+ # C6 无签名缺省:维持默认但可见(不再静默)
175
+ out6 = M._cg_call(cg, {"op": "review"})
176
+ check("C6 无签名缺省走默认 list 且透出",
177
+ "pending" in out6 and out6.get("action_derived") is True
178
+ and out6.get("action") == "list", out6)
179
+ check("C6b hint_action 点名默认 action 便于纠偏",
180
+ "list" in (out6.get("hint_action") or ""), out6)
181
+
182
+ # C7 未知 op 仍 fail-closed(不静默)
183
+ check("C7 未知 op fail-closed 抛错",
184
+ _raises(lambda: M._cg_call(cg, {"op": "not_an_op", "query": "x"})) is not None)
185
+
186
+ # C8 stg 缺 op fail-closed 且提示可操作
187
+ _e8 = _raises(lambda: M._stg_call(None, {"op": ""}))
188
+ check("C8 stg 缺 op fail-closed 且提示必填",
189
+ _e8 is not None and "必填" in str(_e8), _e8)
190
+
191
+ # C9 op 缺省推导仍工作(本轮不回归)
192
+ out9 = M._cg_call(cg, {"content": "op 推导回归探针", "layer": "knowledge"})
193
+ check("C9 op 缺省推导仍透出 op_derived",
194
+ out9.get("op_derived") is True and out9.get("op") == "write", out9)
195
+ finally:
196
+ import shutil
197
+ shutil.rmtree(root, ignore_errors=True)
198
+
199
+ print("=" * 60)
200
+ print("action_derive:%d 通过 / %d 失败" % (_ok, len(_fail)))
201
+ if _fail:
202
+ print("失败项:" + "; ".join(_fail))
203
+ sys.exit(1 if _fail else 0)
@@ -0,0 +1,270 @@
1
+ # -*- coding: utf-8 -*-
2
+ """审计日志分片轮转验证(治本:给无上界增长装上界)。
3
+
4
+ 背景(第 4 条取证,2026-09-16):审计日志无上界增长——实测 ~2 条/s 持续写入、
5
+ 累计 ~21.5 M 条 / 4.0 GB,且单文件形态使任何「读它」的操作随运行时长线性劣化。
6
+ 上一轮把**体检读数**降为 O(1) 元数据口径(_log_scale),只让「指标与代价错配」
7
+ 不再显形;**有界性的来源是轮转**:单文件 ≤ AUDIT_ROTATE_BYTES、分片数 ≤
8
+ AUDIT_KEEP_SHARDS ⇒ 单片读取代价与总量都有上界。
9
+
10
+ 断言面:
11
+ ① 未达阈值不轮转(不产生空转切分)
12
+ ② 达阈值切分:产生归档分片、活动文件被重建
13
+ ③ 切分无损:轮转前记录序列是轮转后序列的前缀(rename 不动字节)
14
+ ④ 轮转自述留痕(首条新记录 op=audit_rotate,不静默)
15
+ ⑤ audit_scale 聚合口径 == 全量写入条数(分片走索引 + 活动实时)
16
+ ⑥ audit_records 跨分片按时间序合并 / limit 取尾部
17
+ ⑦ 保留策略:超 keep 淘汰最旧分片且索引同步
18
+ ⑧ health_os 透出轮转面(shards/total_bytes/total_exact)
19
+ ⑨ 可关闭:ROTATE_BYTES=0 → 不切分(退回无上界,供对照/应急)
20
+ ⑩ 超大历史分片分档读数:exact=False 且**零全量计数**(O(n) 守卫——否则刚修好的
21
+ 「一次调用堵死通道」会在轮转路径上原样复现)
22
+ ⑪ 稳态 O(1):二次 audit_scale 不重数分片(索引缓存生效)
23
+ ⑫ 归档目录不在 LAYERS → 不参与节点索引
24
+
25
+ 运行:python -m md_cg.test_audit_rotate
26
+ """
27
+ from __future__ import annotations
28
+
29
+ import os
30
+ import shutil
31
+ import tempfile
32
+
33
+ from . import mdcos as mdcos_mod
34
+ from .mdcos import MdCGOS
35
+
36
+ PASS = FAIL = 0
37
+ FAILS = []
38
+
39
+
40
+ def ok(cond, label):
41
+ global PASS, FAIL
42
+ if cond:
43
+ PASS += 1
44
+ else:
45
+ FAIL += 1
46
+ FAILS.append(label)
47
+ print(f" FAIL {label}")
48
+
49
+
50
+ class _Spy:
51
+ """记录 mdcos 模块级 count_jsonl / read_jsonl 的调用路径(O(n) 守卫)。"""
52
+
53
+ def __enter__(self):
54
+ self.read, self.count = [], []
55
+ self._read, self._count = mdcos_mod.read_jsonl, mdcos_mod.count_jsonl
56
+ spy = self
57
+
58
+ def _r(p, *a, **k):
59
+ spy.read.append(p)
60
+ return spy._read(p, *a, **k)
61
+
62
+ def _c(p, *a, **k):
63
+ spy.count.append(p)
64
+ return spy._count(p, *a, **k)
65
+
66
+ mdcos_mod.read_jsonl, mdcos_mod.count_jsonl = _r, _c
67
+ return self
68
+
69
+ def __exit__(self, *exc):
70
+ mdcos_mod.read_jsonl, mdcos_mod.count_jsonl = self._read, self._count
71
+ return False
72
+
73
+
74
+ def _mk(tmp, name, rotate=2048, keep=8, probe=1, count_max=None):
75
+ root = os.path.join(tmp, name)
76
+ os.makedirs(root, exist_ok=True)
77
+ cg = MdCGOS(root)
78
+ cg.AUDIT_ROTATE_BYTES = rotate
79
+ cg.AUDIT_KEEP_SHARDS = keep
80
+ cg.AUDIT_PROBE_EVERY = probe
81
+ if count_max is not None:
82
+ cg.AUDIT_COUNT_MAX_BYTES = count_max
83
+ return cg
84
+
85
+
86
+ def _fill(cg, n, tag="x"):
87
+ for i in range(n):
88
+ cg._audit("add", "node_%s_%d" % (tag, i), pad="z" * 160)
89
+
90
+
91
+ def main():
92
+ tmp = tempfile.mkdtemp(prefix="mdcg_rotate_")
93
+ try:
94
+ # ================= A:基本轮转 + 无损 + 聚合 + 尾部读 =================
95
+ cg = _mk(tmp, "a", rotate=(1 << 30)) # 先给超大阈值 → 不轮转
96
+ _fill(cg, 20, "p")
97
+
98
+ # ---------- ① 未达阈值不轮转 ----------
99
+ ok(not cg._audit_shards(),
100
+ "①未达阈值 → 零分片(无空转切分)")
101
+ ok(os.path.getsize(cg.audit_log) > 0 and len(cg.audit_records()) == 20,
102
+ "①b活动文件承载全部记录(20 条),不提前分片")
103
+
104
+ before = [r.get("id") for r in cg.audit_records()]
105
+
106
+ # ---------- ② 达阈值切分 ----------
107
+ cg.AUDIT_ROTATE_BYTES = 2048
108
+ _fill(cg, 20, "q")
109
+ shards = cg._audit_shards()
110
+ ok(len(shards) >= 1,
111
+ "②达阈值 → 产生归档分片(%s)" % (shards or "无"))
112
+ ok(all(n.startswith("_audit.") and n.endswith(".jsonl") for n in shards),
113
+ "②b分片命名规范(_audit.<6位序号>.jsonl,字典序==时间序)")
114
+ ok(os.path.exists(cg.audit_log),
115
+ "②c活动文件被重建(最新记录始终在 _audit.jsonl,读尾调用方不受影响)")
116
+
117
+ # ---------- ③ 切分无损 ----------
118
+ after = cg.audit_records()
119
+ ids = [r.get("id") for r in after if r.get("op") != "audit_rotate"]
120
+ ok(ids[:len(before)] == before,
121
+ "③轮转不丢记录:轮转前序列是轮转后序列的前缀(%d→%d 条)"
122
+ % (len(before), len(after)))
123
+ ok(len(after) == len(before) + 20 + len([r for r in after
124
+ if r.get("op") == "audit_rotate"]),
125
+ "③b条数守恒:轮转前 %d + 新增 20 + 自述 %d == %d"
126
+ % (len(before), len([r for r in after if r.get("op") == "audit_rotate"]),
127
+ len(after)))
128
+
129
+ # ---------- ④ 自述留痕 ----------
130
+ marks = [r for r in after if r.get("op") == "audit_rotate"]
131
+ ok(bool(marks) and marks[0].get("id") in shards,
132
+ "④轮转自述留痕(op=audit_rotate,id 指向分片名,不静默)")
133
+
134
+ # ---------- ⑤ 聚合口径 ----------
135
+ sc = cg.audit_scale()
136
+ ok(sc["total_events"] == len(after) and sc["total_exact"] is True,
137
+ "⑤audit_scale 聚合 == 全量写入条数(%s vs %d),且标注精确"
138
+ % (sc["total_events"], len(after)))
139
+ ok(sc["shards"] == len(shards) and sc["oversized"] == 0,
140
+ "⑤b分片计数 + 零超大分片(阈值内分片走精确计数)")
141
+ ok(sc["total_bytes"] == sc["bytes"] + sc["shard_bytes"],
142
+ "⑤c总量字节 = 活动 + 分片(%d = %d + %d)"
143
+ % (sc["total_bytes"], sc["bytes"], sc["shard_bytes"]))
144
+ ok(sc["rotate_bytes"] == 2048 and sc["keep_shards"] == 8,
145
+ "⑤d读数透出轮转参数(有界性可观测,不用猜配置)")
146
+
147
+ # ---------- ⑥ 跨分片合并 / limit 尾部读 ----------
148
+ tail = cg.audit_records(limit=3)
149
+ ok(len(tail) == 3 and [r.get("id") for r in tail]
150
+ == [r.get("id") for r in after[-3:]],
151
+ "⑥limit=3 取尾部 3 条(巡检不必把有界日志读成全量)")
152
+
153
+ # ---------- ⑧ health_os 透出轮转面 ----------
154
+ o = cg.health_os()["os"]
155
+ ok(o["audit_shards"] == len(shards) and o["audit_total_exact"] is True
156
+ and o["audit_total_bytes"] == sc["total_bytes"],
157
+ "⑧health_os 透出轮转面(shards/total_bytes/total_exact)")
158
+
159
+ # ---------- ⑪ 稳态 O(1):索引缓存生效 ----------
160
+ # 口径:守的是「分片不被重数」(分片走索引缓存);活动文件的精确计数是
161
+ # **有界**代价(size ≤ AUDIT_ROTATE_BYTES),属设计内。
162
+ with _Spy() as spy:
163
+ sc2 = cg.audit_scale()
164
+ ok(not any(os.path.basename(p) in shards for p in spy.count),
165
+ "⑪二次 audit_scale 未重数任何分片(走索引缓存)[count=%s]" % spy.count)
166
+ ok(sc2["total_events"] == sc["total_events"],
167
+ "⑪b稳态读数一致(%s == %s),缓存不改变结论"
168
+ % (sc2["total_events"], sc["total_events"]))
169
+
170
+ # ---------- ⑫ 归档目录不参与节点索引 ----------
171
+ ok(not any("_audit" in k for k in cg.index["nodes"]),
172
+ "⑫归档目录不在 LAYERS → 分片不参与节点索引(检索面零污染)")
173
+
174
+ cg.close()
175
+
176
+ # ================= B:保留策略(淘汰最旧分片) =================
177
+ cgb = _mk(tmp, "b", rotate=2048, keep=2)
178
+ _fill(cgb, 60, "b")
179
+ sb = cgb._audit_shards()
180
+ ok(len(sb) == 2,
181
+ "⑦分片数受 keep 约束(保留最近 2 片,实际 %d)" % len(sb))
182
+ pruned = [r for r in cgb.audit_records() if r.get("op") == "audit_rotate"
183
+ and r.get("pruned")]
184
+ ok(bool(pruned) and len(pruned[0]["pruned"]) >= 1,
185
+ "⑦b淘汰非静默:pruned 名单写进审计(%s)"
186
+ % (pruned[0]["pruned"] if pruned else "无"))
187
+ idx = cgb._load_audit_index()
188
+ ok(all(n in idx for n in sb) and all(n in sb for n in idx),
189
+ "⑦c索引与磁盘分片对齐(淘汰即摘索引,不留悬空项)")
190
+ cgb.close()
191
+
192
+ # ================= C:可关闭(退回无上界) =================
193
+ cgc = _mk(tmp, "c", rotate=0)
194
+ _fill(cgc, 40, "c")
195
+ ok(not cgc._audit_shards() and os.path.getsize(cgc.audit_log) > 0,
196
+ "⑨ROTATE_BYTES=0 → 不切分(应急/对照可退回无上界形态)")
197
+ cgc.close()
198
+
199
+ # ================= D:超大历史分片分档(O(n) 守卫) =================
200
+ cgd = _mk(tmp, "d", rotate=2048, keep=8, count_max=512)
201
+ _fill(cgd, 20, "d")
202
+ sd = cgd._audit_shards()
203
+ ok(bool(sd), "⑩超大分档前置:至少产生 1 个分片(%s)" % (sd or "无"))
204
+ with _Spy() as spy:
205
+ scd = cgd.audit_scale()
206
+ ok(scd["oversized"] >= 1 and scd["total_exact"] is False,
207
+ "⑩b历史超大分片 → oversized=%d、total_exact=False(不假装精确)"
208
+ % scd["oversized"])
209
+ ok(not any(os.path.basename(p) in sd for p in spy.count),
210
+ "⑩c超大分片零全量计数(走 _log_scale 元数据口径)——"
211
+ "否则「一次调用堵死通道」会在轮转路径上复现")
212
+ cgd.close()
213
+
214
+ # ================= E:真实规模(~113 MB 活动文件)轮转不得全量解析 =====
215
+ # 这是「4.0 GB 历史日志」场景的等价缩小版:轮转必须只做 rename(O(1)),
216
+ # 绝不能在写路径上解析整个文件——否则刚修好的「通道被堵死」原样复现。
217
+ import json as _json
218
+ import time as _time
219
+
220
+ cge = _mk(tmp, "e", rotate=64 << 20, keep=8, probe=1)
221
+ line = _json.dumps({"t": 1.0, "op": "add", "id": "bulk",
222
+ "pad": "z" * 200}) + "\n"
223
+ with open(cge.audit_log, "w", encoding="utf-8") as f:
224
+ for _ in range(70): # 70 × ~1.6 MB ≈ 113 MB
225
+ f.write(line * 7000)
226
+ size_bulk = os.path.getsize(cge.audit_log)
227
+ rss0 = None
228
+ try:
229
+ import psutil
230
+ rss0 = psutil.Process(os.getpid()).memory_info().rss
231
+ except Exception: # noqa: BLE001 —— 无 psutil 则不假装
232
+ pass
233
+ t0 = _time.time()
234
+ cge._audit("add", "after_bulk") # 探测到超阈值 → 触发轮转
235
+ rotate_dt = _time.time() - t0
236
+ ok(rotate_dt < 5.0,
237
+ "⑬超大活动文件(%.0f MB)轮转在秒级完成(%.2fs)——rename O(1),"
238
+ "写路径不解析全量" % (size_bulk / 1048576.0, rotate_dt))
239
+ se = cge._audit_shards()
240
+ idxe = cge._load_audit_index()
241
+ ok(len(se) == 1 and idxe[se[0]]["bytes"] == size_bulk,
242
+ "⑬b超大分片登记字节 == 轮转前大小(%d),内容未重写"
243
+ % size_bulk)
244
+ ok(idxe[se[0]]["exact"] is False,
245
+ "⑬c超大分片条数走元数据口径(exact=False,不假装精确)")
246
+ t1 = _time.time()
247
+ sce = cge.audit_scale()
248
+ scale_dt = _time.time() - t1
249
+ ok(sce["oversized"] == 1 and sce["total_bytes"] >= size_bulk,
250
+ "⑬d体检识别 oversized=%d、总量 %.0f MB(历史分片仍在总量核算内)"
251
+ % (sce["oversized"], sce["total_bytes"] / 1048576.0))
252
+ if rss0 is not None:
253
+ import psutil
254
+ rss_delta = psutil.Process(os.getpid()).memory_info().rss - rss0
255
+ ok(rss_delta < (300 << 20) and scale_dt < 2.0,
256
+ "⑬e轮转+体检 RSS 增量 %.0f MB < 300 MB、体检 %.2fs —— 不物化不阻塞"
257
+ % (rss_delta / 1048576.0, scale_dt))
258
+ cge.close()
259
+ finally:
260
+ shutil.rmtree(tmp, ignore_errors=True)
261
+
262
+ print(f"\naudit_rotate: {PASS} pass / {FAIL} fail")
263
+ if FAILS:
264
+ for f in FAILS:
265
+ print(f" - {f}")
266
+ raise SystemExit(1 if FAIL else 0)
267
+
268
+
269
+ if __name__ == "__main__":
270
+ main()
@@ -7,6 +7,8 @@
7
7
  提案携带证据明细
8
8
  ③ 全链路:提案 → learn_blindspots 五态终判 → 留痕 _explore.jsonl
9
9
  ④ 幂等:重复 explore 终态一致、gap 回写不重复(gap_<sha1(bid)> 幂等)
10
+ ⑤ D_meta 排序加分:只进 sort_score 与证据,不改 score、不改资格
11
+ (零信号查询仍不提案;加分每轮一次、循环内复用)
10
12
 
11
13
  运行:python -m md_cg.test_autonomy
12
14
  """
@@ -103,6 +105,30 @@ def main():
103
105
  "④b gap 回写幂等(第二次 written=None,节点已存在)")
104
106
  else:
105
107
  ok(True, "④b本终态无回写动作,幂等性由判定确定性保证")
108
+
109
+ # ---------- ⑤ D_meta 排序加分(只影响排序,不改资格) ----------
110
+ root5 = os.path.join(tmp, "root5")
111
+ os.makedirs(root5, exist_ok=True)
112
+ cg5 = MdCGOS(root5)
113
+ for i in range(50):
114
+ append_jsonl(cg5.recent_log, {"i": i})
115
+ _sig(cg5, 1.0, "零信号查询", 0.0, {})
116
+ _sig(cg5, 2.0, "反应堆冷却方案", 0.9, {"BLINDSPOT": 2})
117
+ pr5 = autonomy.proposals(cg5, limit=3)
118
+ ps5 = pr5["proposals"]
119
+ ok(len(ps5) == 1 and pr5["n_signals"] == 2,
120
+ "⑤零信号查询仍不提案、n_signals 按原始信号计(加分不改资格)")
121
+ p0 = ps5[0]
122
+ ok(p0["score"] == round(autonomy.W_D2 * p0["d2_abs"]
123
+ + autonomy.W_BLINDSPOT * p0["blindspot"]
124
+ + autonomy.W_DEFER * p0["defer"], 4),
125
+ "⑤bscore 仍是纯 ΔD 定价(口径零变更)")
126
+ ok(p0["sort_score"] == round(p0["score"] + p0["d_meta_bonus"], 4)
127
+ and p0["d_meta_bonus"] == pr5["d_meta"]["bonus"],
128
+ "⑤c排序键 = ΔD + D_meta 加分(每轮一次、循环内复用)")
129
+ ok(p0["d_meta_bonus"] > 0 and "D_meta" in p0["reason"]
130
+ and "不合成" in p0["reason"],
131
+ "⑤d加分生效且 reason 追加证据并声明不合成(可审计)")
106
132
  finally:
107
133
  shutil.rmtree(tmp, ignore_errors=True)
108
134
 
@@ -0,0 +1,102 @@
1
+ # -*- coding: utf-8 -*-
2
+ """bench_governance 评估器断言测试:语料守卫/指标定义/确定性/输出结构。"""
3
+ import json
4
+ import os
5
+ import shutil
6
+ import tempfile
7
+ import time
8
+
9
+ from . import bench_governance as bg
10
+
11
+ _FAILED = []
12
+
13
+
14
+ def ok(cond, label):
15
+ if not cond:
16
+ print("FAIL", label)
17
+ _FAILED.append(label)
18
+ else:
19
+ print("pass", label)
20
+
21
+
22
+ def main():
23
+ # ① 语料守卫:当前语料必须合法
24
+ try:
25
+ bg._assert_material(time.time())
26
+ ok(True, "① 语料守卫通过(当前语料合法)")
27
+ except AssertionError as exc:
28
+ ok(False, f"① 语料守卫意外失败:{exc}")
29
+
30
+ # ② 篡改语料必须被守卫拦截(不可答题泄漏语料词面)
31
+ saved = list(bg.UNANSWERABLE)
32
+ try:
33
+ bg.UNANSWERABLE.append("蜂巢心跳间隔是多少")
34
+ try:
35
+ bg._assert_material(time.time())
36
+ ok(False, "② 篡改语料未被拦截")
37
+ except AssertionError:
38
+ ok(True, "② 篡改语料被守卫拦截")
39
+ finally:
40
+ bg.UNANSWERABLE[:] = saved
41
+
42
+ # ③ 全流程跑通 + 指标定义断言
43
+ report, root = bg.run()
44
+ try:
45
+ g1 = report["g1_correction_propagation"]
46
+ ok(g1["value"] == 1.0, f"③a g1 完美传播=1.0(got {g1['value']})")
47
+ ok(g1["detail"]["dependents"] == 4 and g1["detail"]["updated"] == 4,
48
+ "③b g1 依赖索引=4 且全部同步")
49
+
50
+ g2 = report["g2_contradiction_handling"]
51
+ ok(g2["value"] == 1.0, f"③c g2 矛盾裁决全对=1.0(got {g2['value']},detail={g2['detail']})")
52
+ ok(all(j["state"] == "REJECT" for j in g2["detail"]["judged"]),
53
+ "③d 否定节点定点裁决全 REJECT")
54
+ ok(g2["detail"]["retrieval"]["leaked_negatives"] == [],
55
+ "③e 检索防线 top-k 无否定节点冒充")
56
+
57
+ g3 = report["g3_expired_recall"]
58
+ ok(g3["value"] == 0.0, f"③f g3 validity 防线残留=0(got {g3['value']})")
59
+ ok(g3["detail"]["raw"]["stale_hits"], "③g 默认面确实暴露过期节点(同题竞争成立)")
60
+ ok(not g3["detail"]["guard"]["stale_hits"], "③h guard 面 top-k 无过期节点")
61
+
62
+ g4 = report["g4_refusal_f1"]
63
+ d4 = g4["detail"]
64
+ ok(d4["tp"] + d4["fn"] == len(bg.UNANSWERABLE), "③i 不可答集计数守恒")
65
+ ok(d4["fp"] + d4["tn"] == len(bg.FACTS), "③j 可答集计数守恒")
66
+ ok(g4["value"] is not None and 0.0 <= g4["value"] <= 1.0,
67
+ f"③k g4 F1 在 [0,1](got {g4['value']})")
68
+
69
+ ok(report["meta"]["corpus_nodes"] >= 20, "③l 语料规模守卫")
70
+ ok(all(report[g]["value"] is not None for g in
71
+ ("g1_correction_propagation", "g2_contradiction_handling",
72
+ "g3_expired_recall", "g4_refusal_f1")), "③m 四指标均可计算")
73
+ finally:
74
+ shutil.rmtree(root, ignore_errors=True)
75
+
76
+ # ④ 确定性:重跑逐位一致
77
+ r1, root1 = bg.run()
78
+ r2, root2 = bg.run()
79
+ shutil.rmtree(root1, ignore_errors=True)
80
+ shutil.rmtree(root2, ignore_errors=True)
81
+ strip = lambda r: {g: r[g]["value"] for g in r if g.startswith("g")} # noqa: E731
82
+ ok(strip(r1) == strip(r2), "④ 两次运行四指标逐位一致")
83
+
84
+ # ⑤ main 输出 JSON 可写且结构完整
85
+ tmp_dir = tempfile.mkdtemp(prefix="gov_out_")
86
+ try:
87
+ tmp_out = os.path.join(tmp_dir, "baseline.json")
88
+ rc = bg.main(["--out", tmp_out])
89
+ with open(tmp_out, encoding="utf-8") as f:
90
+ data = json.load(f)
91
+ ok(rc == 0 and {"meta", "g1_correction_propagation", "g2_contradiction_handling",
92
+ "g3_expired_recall", "g4_refusal_f1",
93
+ "baseline_reference"} <= set(data), "⑤ 输出 JSON 结构完整且 exit 0")
94
+ finally:
95
+ shutil.rmtree(tmp_dir, ignore_errors=True)
96
+
97
+ print("\nbench_governance selftest: %d failed" % len(_FAILED))
98
+ return 1 if _FAILED else 0
99
+
100
+
101
+ if __name__ == "__main__":
102
+ raise SystemExit(main())