@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,123 @@
1
+ # -*- coding: utf-8 -*-
2
+ """盲区消解票据(阶段三 §5.4):BLINDSPOT/DEFER 盲区 → 四类消解票据(任务卡形态)挂认知图。
3
+
4
+ 四类分类判据(确定性、声明式、可审计,不做语义猜测):
5
+ task — 盲区 query 精确命中某 unresolved 层节点正文首行 → 直接立工程任务卡
6
+ grilling — defer 主导(defer > blindspot,信息不完整须澄清);执行通道=宿主侧
7
+ 访谈(grill),md_cg 库内无访谈工具,本模块只建卡不越权代答(边界如实)
8
+ research — blindspot >= 3(反复未知)→ 研究议题(检索/调研补证)
9
+ prototype — 其余 → 最小探针实验验证
10
+
11
+ 幂等:tasks.upsert 同 slug 即同任务,重复生成不新建卡(updated 计数)。
12
+ 依赖挂接:票据即任务节点(认知图节点天然在图上、可检索)。「升级为正式工程
13
+ 任务时的机械 depends_on 边」由使用者在该卡更新时显式填写——本模块不伪造
14
+ 工程边,消解路径以正文声明。
15
+ 预演:apply=False 只出清单不落库(与 learn/reconstruct 的 opt-in 同构,
16
+ 默认链路零变更)。
17
+ """
18
+ from . import metacognition, tasks
19
+
20
+ TICKET_TYPES = ("research", "prototype", "grilling", "task")
21
+
22
+ _RESOLVE = {
23
+ "research": "检索/调研补证(外部研究系列吸收流程),产出知识节点后复核 gap_hint",
24
+ "prototype": "构造最小探针实验验证,结论回写认知图",
25
+ "grilling": "澄清缺位:执行通道=宿主侧访谈(grill);库内无访谈工具,不越权代答",
26
+ "task": "直接立工程任务推进(关联 unresolved 悬挂线索)",
27
+ }
28
+
29
+ _JUDGE = {
30
+ "research": "blindspot>=3(反复未知 → 研究议题)",
31
+ "prototype": "其余(偶发未知 → 最小探针)",
32
+ "grilling": "defer 主导(信息不完整 → 须澄清)",
33
+ "task": "query 精确命中 unresolved 节点正文首行",
34
+ }
35
+
36
+
37
+ def classify(item, unresolved_first_lines):
38
+ """按确定性判据给盲区分派票据类型。unresolved_first_lines={首行: node_id}。"""
39
+ q = str(item.get("query") or "").strip()
40
+ if q and q in unresolved_first_lines:
41
+ return "task"
42
+ b = int(item.get("blindspot") or 0)
43
+ d = int(item.get("defer") or 0)
44
+ if d > b:
45
+ return "grilling"
46
+ if b >= 3:
47
+ return "research"
48
+ return "prototype"
49
+
50
+
51
+ def _plan_text(item, ttype, unresolved_first_lines):
52
+ q = str(item.get("query") or "").strip()
53
+ lines = [
54
+ "来源:盲区簇 key=%s(blindspot=%s defer=%s samples=%s)" % (
55
+ metacognition._key(q), item.get("blindspot"), item.get("defer"),
56
+ item.get("samples")),
57
+ "分类判据:%s" % _JUDGE[ttype],
58
+ ]
59
+ if ttype == "task" and q in unresolved_first_lines:
60
+ lines.append("关联悬挂:unresolved 节点 %s" % unresolved_first_lines[q])
61
+ lines.append("消解路径:%s" % _RESOLVE[ttype])
62
+ lines.append("完成判据:盲区簇后续反思记录中 BLINDSPOT/DEFER 归零(gap_hint 复核)")
63
+ return "\n".join(lines)
64
+
65
+
66
+ def make_tickets(cg, *, types=None, limit=10, min_blindspot=0,
67
+ apply=False, actor=None) -> dict:
68
+ """盲区 → 消解票据。apply=False 预演(零落库);apply=True 经 tasks.upsert 落卡。"""
69
+ want = tuple(t for t in (types or TICKET_TYPES) if str(t).strip())
70
+ bad = [t for t in want if str(t).strip().lower() not in TICKET_TYPES]
71
+ if bad:
72
+ return {"ok": False,
73
+ "error": "未知票据类型:%s(可选 %s)" % (bad, list(TICKET_TYPES))}
74
+
75
+ mp = metacognition.blindspots(cg, limit=max(int(limit), 20))
76
+ items = []
77
+ for it in mp.get("items") or []:
78
+ b = int(it.get("blindspot") or 0)
79
+ d = int(it.get("defer") or 0)
80
+ if b >= int(min_blindspot) or d >= 1:
81
+ items.append(it)
82
+
83
+ unresolved_first_lines = {}
84
+ for u in mp.get("unresolved") or []:
85
+ first = str(u.get("content") or "").strip().splitlines()
86
+ if first and first[0].strip():
87
+ unresolved_first_lines.setdefault(first[0].strip(), u.get("node_id"))
88
+
89
+ out, created, updated, errors = [], 0, 0, 0
90
+ for it in items[:int(limit)]:
91
+ q = str(it.get("query") or "").strip()
92
+ if not q:
93
+ continue
94
+ ttype = classify(it, unresolved_first_lines)
95
+ if ttype not in [str(t).strip().lower() for t in want]:
96
+ out.append({"type": ttype, "query": q, "skipped": "types 过滤"})
97
+ continue
98
+ name = "票据:%s:%s" % (ttype, q[:24])
99
+ if not apply:
100
+ out.append({"type": ttype, "query": q, "name": name, "dry_run": True})
101
+ continue
102
+ r = tasks.upsert(
103
+ cg, name, plan=_plan_text(it, ttype, unresolved_first_lines),
104
+ status="active",
105
+ note="盲区簇 key=%s|blindspot=%s|defer=%s" % (
106
+ metacognition._key(q), it.get("blindspot"), it.get("defer")),
107
+ tags=["blindspot-ticket", "ticket:%s" % ttype],
108
+ actor=actor or "blindspot_tickets")
109
+ if r.get("ok"):
110
+ if r.get("created"):
111
+ created += 1
112
+ else:
113
+ updated += 1
114
+ out.append({"node_id": r.get("node_id"), "type": ttype,
115
+ "query": q, "created": bool(r.get("created"))})
116
+ else:
117
+ errors += 1
118
+ out.append({"type": ttype, "query": q, "error": r.get("error")})
119
+
120
+ return {"ok": errors == 0, "action": "tickets", "op": "insight",
121
+ "scanned": len(items), "created": created, "updated": updated,
122
+ "errors": errors, "applied": bool(apply), "tickets": out,
123
+ "unresolved_count": len(unresolved_first_lines)}
@@ -0,0 +1,286 @@
1
+ # -*- coding: utf-8 -*-
2
+ """记忆演化分支(Pi 机制移植④,交接文档 §3④「记忆演化 fork」,P0)。
3
+
4
+ pi:会话 = entry 树,任意历史节点可 fork;被放弃旁支由 branch_summary
5
+ 归档定长摘要。灵枢映射(单一演化线 → 假设分支实验场):
6
+
7
+ - fork:把主支节点复制成分支实验副本(fm.branch_id / branched_from),
8
+ 副本 derived_from=[主支]、relation="split_from"——血缘单向可回溯;
9
+ - 分支节点默认从主支检索隐身(_candidates 按 branch 过滤,一处生效
10
+ 全链路穿透)——实验不污染主支(验收:召回主支时分支节点零命中);
11
+ - merge:按 branched_from 溯源回写主支(derived_from=[分支 nid] 追加进
12
+ 主支原链、relation="merged_from"),override 走快照——合并后链完整;
13
+ - discard:校验 BRANCH_MARKS 必填 → 写教训节点(knowledge 层、可检索)
14
+ → 分支文件移入冷区 _branches/<id>/(物理保留、索引摘除、永不删除)。
15
+
16
+ 与 writepipe 同哲学:库层函数收 cg,权限闸保持库层强制——
17
+ fork/merge 走 add 的 require_layer_write 自动覆盖;
18
+ discard 改变库可见性,需 can_admin(principal.require_admin)。
19
+ 生命周期事件走 _audit.jsonl(③ 两段式载体,零新日志格式)。
20
+ """
21
+
22
+ import os
23
+ import re
24
+ import uuid
25
+
26
+ #: discard 的 branch_summary 必填标记(复用 NEG_MEMORY_MARKS 的必填防呆模式:
27
+ #: 「假设 + 结果 + 教训」缺一不收——放弃分支必须留下可复用的教训)。
28
+ BRANCH_MARKS = ("分支假设", "实验结果", "教训")
29
+
30
+ #: 分支文件冷区(LAYERS 之外,_scan_nodes 不扫——天然不进索引与检索)。
31
+ COLD_DIR = "_branches"
32
+
33
+ _BRANCH_RE = re.compile(r"^[a-z0-9][a-z0-9_-]{0,63}$")
34
+
35
+
36
+ # 生效条件:调用 branch_tag(branch_id) 时,返回 "branch:" 拼接 str(branch_id or "").strip().lower()(branch_id 为假值时以空串参与拼接)。
37
+ def branch_tag(branch_id: str) -> str:
38
+ """分支节点的标注 tag(fork 时写入;branch_summary 也带它以便反查)。"""
39
+ return "branch:" + str(branch_id or "").strip().lower()
40
+
41
+
42
+ # 生效条件:调用 branch_node_id(orig, branch_id) 时,返回 orig 与 str(branch_id or "").strip().lower() 以 @ 拼接的字符串(branch_id 为假值时用空串)。
43
+ def branch_node_id(orig: str, branch_id: str) -> str:
44
+ """分支副本 id:`<主支nid>@<branch_id>`(@ 文件名合法、撞名不可能)。"""
45
+ return "%s@%s" % (orig, str(branch_id or "").strip().lower())
46
+
47
+
48
+ # 生效条件:调用 _audit(cg, op, **meta) 时,仅当 getattr(cg, "_audit", None) 不为 None 才用 op 等调用之,且该调用抛出的任何 Exception 被静默吞掉;否则直接返回。
49
+ def _audit(cg, op: str, **meta) -> None:
50
+ """生命周期留痕;审计失败绝不阻断主流程(G8 同哲学)。"""
51
+ a = getattr(cg, "_audit", None)
52
+ if a is None:
53
+ return
54
+ try:
55
+ a(op, None, **meta)
56
+ except Exception:
57
+ pass
58
+
59
+
60
+ # 生效条件:调用 _iter_branch_nodes(cg, branch_id) 时,返回 cg.index 的 "nodes" 字典(假值则视为空字典)中所有 v.get("branch_id") 等于 str(branch_id or "").strip().lower() 的 (k, v) 列表。
61
+ def _iter_branch_nodes(cg, branch_id: str):
62
+ bid = str(branch_id or "").strip().lower()
63
+ return [(k, v) for k, v in (cg.index.get("nodes") or {}).items()
64
+ if v.get("branch_id") == bid]
65
+
66
+
67
+ # 生效条件:调用 _fm_of(rec) 时,若 rec 为假值返回 {};否则返回 rec.get("frontmatter")(若该值真)或 rec 本身。
68
+ def _fm_of(rec):
69
+ """get 返回形态兼容:{'frontmatter': fm, 'content': c} 或平铺 fm。"""
70
+ if not rec:
71
+ return {}
72
+ return rec.get("frontmatter") or rec
73
+
74
+
75
+ # 生效条件:调用 fork(cg, node_ids, branch_id=None, note=None) 时,先将 node_ids 去空转字符串,为空则返回 {"ok": False, "error": ...};否则 branch_id 为 None 时生成 "br_"+uuid4().hex[:8],再 str(branch_id).strip().lower(),若不匹配模块常量 _BRANCH_RE 则返回错误;然后对每个 nid 跳过含 "@"、cg.get(nid) 为假值或 cg.get(branch_node_id(nid, branch_id)) 已存在者,其余经 cg.add 复制并记入 forked,最终返回 ok=bool(forked) 及 branch_id/tag/forked/skipped。
76
+ def fork(cg, node_ids, branch_id=None, note=None) -> dict:
77
+ """把主支节点复制成分支实验副本。
78
+
79
+ 返回 {ok, branch_id, tag, forked:[{from,to}], skipped:[{id,why}]}。
80
+ 幂等:同 (主支节点, branch_id) 的副本已存在则 skipped,不重复复制。
81
+ """
82
+ ids = [str(x).strip() for x in (node_ids or []) if str(x).strip()]
83
+ if not ids:
84
+ return {"ok": False, "error": "node_ids 为空(至少指定一个主支节点)"}
85
+ if branch_id is None:
86
+ branch_id = "br_" + uuid.uuid4().hex[:8]
87
+ branch_id = str(branch_id).strip().lower()
88
+ if not _BRANCH_RE.match(branch_id):
89
+ return {"ok": False, "error": "branch_id 非法(%s):%r"
90
+ % (_BRANCH_RE.pattern, branch_id)}
91
+ forked, skipped = [], []
92
+ for nid in ids:
93
+ if "@" in nid:
94
+ skipped.append({"id": nid, "why": "已是分支节点,不支持再 fork"})
95
+ continue
96
+ rec = cg.get(nid)
97
+ if not rec:
98
+ skipped.append({"id": nid, "why": "主支节点不存在或不可见"})
99
+ continue
100
+ fm = _fm_of(rec)
101
+ bid = branch_node_id(nid, branch_id)
102
+ if cg.get(bid):
103
+ skipped.append({"id": nid, "why": "副本已存在:%s" % bid})
104
+ continue
105
+ cg.add(bid, rec.get("content") or "",
106
+ layer=fm.get("layer") or "knowledge",
107
+ role=fm.get("role"),
108
+ tags=list(fm.get("tags") or []),
109
+ condition_space=fm.get("condition_space"),
110
+ importance=float(fm.get("importance", 0.5)),
111
+ verification_basis=fm.get("verification_basis") or "test",
112
+ non_applicable_conditions=fm.get("non_applicable_conditions"),
113
+ consistency=False,
114
+ derived_from=[nid], relation="split_from",
115
+ branch_id=branch_id, branched_from=nid, branch_note=note,
116
+ actor="branch_fork")
117
+ forked.append({"from": nid, "to": bid})
118
+ _audit(cg, "branch_fork", branch_id=branch_id,
119
+ forked=[f["to"] for f in forked])
120
+ return {"ok": bool(forked), "branch_id": branch_id,
121
+ "tag": branch_tag(branch_id), "forked": forked, "skipped": skipped}
122
+
123
+
124
+ # 生效条件:调用 search(cg, query, branch_id, **kw) 时,以 branch=str(branch_id or "").strip().lower() 为参数转调 cg.search,并原样返回其结果。
125
+ def search(cg, query: str, branch_id: str, **kw):
126
+ """分支内检索:主支 + 本分支可见、其他分支隐身(_candidates branch 过滤)。"""
127
+ return cg.search(query, branch=str(branch_id or "").strip().lower(), **kw)
128
+
129
+
130
+ # 生效条件:当 node_id 经 str 转换并 strip 后含 '@'、cg.index['nodes'] 中存在该 id 且其 branch_id 非空、content 不是 dict 且不是 None 时返回 {'ok': True, 'node': nid, 'branch_id': ...},否则返回 {'ok': False, 'error': ...}。
131
+ def rewrite(cg, node_id, content, tags=None, importance=None,
132
+ actor="branch_rewrite", **extra) -> dict:
133
+ """分支实验改写的**唯一正路**(防裸 add 丢分支归属)。
134
+
135
+ 背景:add 是全量重建 fm——裸 add 改写分支节点而不重传 branch_id,
136
+ 节点会在索引里退化成主支(实验内容直接泄漏进主支检索)。本帮手:
137
+ - 只接受在册分支节点(含 @ 且 entry.branch_id 在册);
138
+ - 归属与血缘(branch_id / branched_from / branch_note / derived_from /
139
+ derived_relation)一律从旧 fm 继承,调用方**不可改**(extra 里
140
+ 同名键静默剥离)——「分支上怎么改内容都行,改不了它是谁的实验」;
141
+ - 层/条件空间/验证基底默认继承旧 fm(tags/importance 可显式覆盖);
142
+ - override=True → 旧内容自动快照留痕(③ 快照机制,零新日志)。
143
+ 写权限由 add 的 require_layer_write 库层强制,不在此重复设闸。
144
+ """
145
+ nid = str(node_id or "").strip()
146
+ if "@" not in nid:
147
+ return {"ok": False,
148
+ "error": "非分支节点(须为 <主支>@<branch_id> 形态):%s" % nid}
149
+ e = (cg.index.get("nodes") or {}).get(nid)
150
+ if not e or not e.get("branch_id"):
151
+ return {"ok": False, "error": "分支节点不存在或无分支归属:%s" % nid}
152
+ rec = cg.get(nid)
153
+ fm = _fm_of(rec)
154
+ if isinstance(content, dict) or content is None:
155
+ return {"ok": False, "error": "content 须为字符串"}
156
+ for k in ("branch_id", "branched_from", "branch_note", "derived_from",
157
+ "relation", "merged_from_branch", "override", "consistency"):
158
+ extra.pop(k, None) # 归属/血缘/写法闸不可经 extra 篡改
159
+ cg.add(nid, str(content or ""),
160
+ layer=fm.get("layer") or e.get("layer") or "knowledge",
161
+ tags=list(tags if tags is not None else (fm.get("tags") or [])),
162
+ importance=float(importance if importance is not None
163
+ else (fm.get("importance") or 0.5)),
164
+ condition_space=fm.get("condition_space"),
165
+ verification_basis=fm.get("verification_basis") or "test",
166
+ non_applicable_conditions=fm.get("non_applicable_conditions"),
167
+ override=True, consistency=False,
168
+ derived_from=list(fm.get("derived_from") or []),
169
+ relation=fm.get("derived_relation") or "split_from",
170
+ branch_id=fm.get("branch_id") or e.get("branch_id"),
171
+ branched_from=fm.get("branched_from") or e.get("branched_from"),
172
+ branch_note=fm.get("branch_note"),
173
+ actor=actor, **extra)
174
+ _audit(cg, "branch_rewrite", branch_id=e.get("branch_id"), node=nid)
175
+ return {"ok": True, "node": nid, "branch_id": e.get("branch_id")}
176
+
177
+
178
+ # 生效条件:调用 merge(cg, branch_id, reason=None) 时,先取 bid=str(branch_id or "").strip().lower() 与 _iter_branch_nodes(cg, bid),若结果为空返回 {"ok": False, "error": ...};否则遍历每个分支节点,若其 branched_from 取不到主支节点则记 skipped,否则把分支内容用 cg.add 回写主支(override=True、derived_from 追加分支 nid、relation="merged_from" 等),最终返回 ok=bool(merged) 等。
179
+ def merge(cg, branch_id, reason=None) -> dict:
180
+ """把分支上的改写按 branched_from 溯源回写主支。
181
+
182
+ - 主支内容 = 分支内容;层/tags/重要性继承主支(实验元数据不带回去);
183
+ - 主支 derived_from 追加分支 nid(原链保留)、relation="merged_from";
184
+ - override=True → 主支旧内容自动快照留痕;
185
+ - 分支节点保留(merge 不自动删——显式两步、可逆、诚实)。
186
+ """
187
+ bid = str(branch_id or "").strip().lower()
188
+ ents = _iter_branch_nodes(cg, bid)
189
+ if not ents:
190
+ return {"ok": False, "error": "分支不存在或无节点:%s" % bid}
191
+ merged, skipped = [], []
192
+ for nid, e in ents:
193
+ orig = e.get("branched_from")
194
+ rec = cg.get(orig) if orig else None
195
+ if not rec:
196
+ skipped.append({"id": nid, "why": "主支节点不存在:%s" % orig})
197
+ continue
198
+ src = cg.get(nid)
199
+ old_fm = _fm_of(rec)
200
+ src_fm = _fm_of(src)
201
+ chain = list(old_fm.get("derived_from") or [])
202
+ if nid not in chain:
203
+ chain.append(nid)
204
+ cg.add(orig, (src or {}).get("content") or "",
205
+ layer=old_fm.get("layer") or e.get("layer") or "knowledge",
206
+ tags=list(old_fm.get("tags") or e.get("tags") or []),
207
+ condition_space=src_fm.get("condition_space"),
208
+ importance=float(old_fm.get("importance", 0.5)),
209
+ verification_basis=old_fm.get("verification_basis") or "test",
210
+ non_applicable_conditions=old_fm.get("non_applicable_conditions"),
211
+ override=True, consistency=False,
212
+ derived_from=chain, relation="merged_from",
213
+ merged_from_branch=bid, actor="branch_merge")
214
+ merged.append({"branch_node": nid, "target": orig})
215
+ _audit(cg, "branch_merge", branch_id=bid,
216
+ merged=[m["target"] for m in merged], reason=reason)
217
+ return {"ok": bool(merged), "branch_id": bid, "merged": merged,
218
+ "skipped": skipped,
219
+ "hint": "分支节点保留:可 branch_search 继续实验,或 discard 冷归档"}
220
+
221
+
222
+ # 生效条件:调用 discard(cg, branch_id, summary) 时,若 cg.principal 存在则先 require_admin("branch_discard");取 bid=str(branch_id or "").strip().lower(),若 summary 缺少模块常量 BRANCH_MARKS 中任一标记则返回错误,若 _iter_branch_nodes(cg, bid) 为空也返回错误;否则写 "branch_summary_"+bid 知识节点,把分支节点文件移入 COLD_DIR/bid 并从 cg.index["nodes"] 弹出,最后返回 ok=True 等。
223
+ def discard(cg, branch_id, summary: str) -> dict:
224
+ """放弃分支:校验教训必填 → 写 branch_summary 教训节点 → 分支冷归档。
225
+
226
+ - summary 必须含 BRANCH_MARKS 三标记(缺一不收,防「无声放弃」);
227
+ - 教训节点进 knowledge 层、tags 带 branch:<id>——可被正常检索召回;
228
+ - 分支节点文件移入 _branches/<id>/(物理保留不违背永不删除,
229
+ LAYERS 之外故 _scan_nodes 不再扫到——索引与主支检索天然干净);
230
+ - 需 can_admin(改变库可见性属高危操作)。
231
+ """
232
+ p = getattr(cg, "principal", None)
233
+ if p is not None:
234
+ p.require_admin("branch_discard")
235
+ bid = str(branch_id or "").strip().lower()
236
+ missing = [m for m in BRANCH_MARKS if m not in (summary or "")]
237
+ if missing:
238
+ return {"ok": False, "error": "branch_summary 缺必填标记",
239
+ "missing": missing, "required": list(BRANCH_MARKS)}
240
+ ents = _iter_branch_nodes(cg, bid)
241
+ if not ents:
242
+ return {"ok": False, "error": "分支不存在或无节点:%s" % bid}
243
+ body = summary if summary.lstrip().startswith("#") else \
244
+ "# branch_summary:%s\n\n%s" % (bid, summary)
245
+ sid = cg.add("branch_summary_%s" % bid, body, layer="knowledge",
246
+ tags=["branch_summary", branch_tag(bid)],
247
+ verification_basis="test", consistency=False,
248
+ actor="branch_discard")
249
+ cold = os.path.join(cg.root, COLD_DIR, bid)
250
+ os.makedirs(cold, exist_ok=True)
251
+ moved = 0
252
+ for nid, e in ents:
253
+ path = e.get("path")
254
+ if path:
255
+ src = os.path.join(cg.root, str(path).replace("/", os.sep))
256
+ if os.path.exists(src):
257
+ os.replace(src, os.path.join(cold, os.path.basename(src)))
258
+ moved += 1
259
+ (cg.index.get("nodes") or {}).pop(nid, None)
260
+ fl = getattr(cg, "flush", None)
261
+ if fl is not None:
262
+ try:
263
+ fl()
264
+ except Exception:
265
+ pass
266
+ _audit(cg, "branch_discard", branch_id=bid, moved=moved, summary_node=sid)
267
+ return {"ok": True, "branch_id": bid, "moved": moved,
268
+ "summary_node": sid, "cold_dir": "%s/%s" % (COLD_DIR, bid)}
269
+
270
+
271
+ # 生效条件:调用 list_branches(cg) 时,遍历 cg.index 的 "nodes"(假值则空字典),仅对 e.get("branch_id") 为真值的节点按 bid 分组,收集节点 id 和 branched_from,返回 ok=True 与按 branch_id 排序的分组列表。
272
+ def list_branches(cg) -> dict:
273
+ """按 branch_id 聚合现存分支(节点清单 + 溯源主支)。"""
274
+ groups = {}
275
+ for nid, e in (cg.index.get("nodes") or {}).items():
276
+ bid = e.get("branch_id")
277
+ if not bid:
278
+ continue
279
+ g = groups.setdefault(bid, {"branch_id": bid, "tag": branch_tag(bid),
280
+ "nodes": [], "branched_from": []})
281
+ g["nodes"].append(nid)
282
+ bf = e.get("branched_from")
283
+ if bf and bf not in g["branched_from"]:
284
+ g["branched_from"].append(bf)
285
+ return {"ok": True,
286
+ "branches": sorted(groups.values(), key=lambda g: g["branch_id"])}
@@ -0,0 +1,73 @@
1
+ # -*- coding: utf-8 -*-
2
+ """倒排发布表构建/查看(S7 候选层)。
3
+
4
+ 用法:
5
+ python -X utf8 -m md_cg.build_postings --root <库根> # 全量重建(幂等)
6
+ python -X utf8 -m md_cg.build_postings --root <库根> --stats # 只看现状
7
+ python -X utf8 -m md_cg.build_postings --root <库根> --limit 500 # 抽样构建(冒烟用,永不算新鲜)
8
+ python -X utf8 -m md_cg.build_postings --root <库根> --if-stale # 过期才重建(守候环用)
9
+
10
+ 说明:发布表是**派生索引**(<root>/_postings.json + _postings_meta.json),
11
+ 不修改任何节点内容;节点新增/修改后需重建(v1 不做增量维护)。
12
+ """
13
+ import argparse
14
+ import json
15
+ import sys
16
+
17
+ from . import postings
18
+ from .mdcg import MdCG
19
+
20
+
21
+ # 生效条件:st 为 dict 时返回其摘要——保留 schema/built_at/nodes/terms/postings/partial/rebuilt/rebuilt_from,
22
+ # 并把 snapshot 折成 dirs/root_files 计数(快照本体含上千个目录键,直接打印会淹没日志);st 非 dict 时原样返回。
23
+ def _brief(st):
24
+ if not isinstance(st, dict):
25
+ return st
26
+ keys = ("schema", "built_at", "nodes", "terms", "postings", "partial",
27
+ "rebuilt", "rebuilt_from")
28
+ out = {k: st.get(k) for k in keys if k in st}
29
+ snap = st.get("snapshot")
30
+ if isinstance(snap, dict):
31
+ out["dirs"] = len(snap.get("dir_mtimes") or {})
32
+ out["root_files"] = len(snap.get("file_mtimes") or {})
33
+ return out
34
+
35
+
36
+ # 生效条件:无条件解析参数(root 必填;stats/limit/if-stale 可选;if-stale 与 limit 互斥则 argparse 报错并退出 2);
37
+ # stats 为真时打开库打印 stats 摘要(含 stale_reason)并返回 0;if-stale 为真且快照新鲜时打印 {"rebuilt": false} 返回 0、
38
+ # 过期时重建并打印摘要(附 rebuilt_from=过期原因);否则一律重建并打印摘要,返回 0。
39
+ # 三条路径打印的都是 _brief 摘要——不打印快照指纹本体。
40
+ def main(argv=None):
41
+ ap = argparse.ArgumentParser()
42
+ ap.add_argument("--root", required=True)
43
+ ap.add_argument("--stats", action="store_true")
44
+ ap.add_argument("--limit", type=int, default=None)
45
+ ap.add_argument("--if-stale", action="store_true", dest="if_stale")
46
+ a = ap.parse_args(argv)
47
+ if a.if_stale and a.limit:
48
+ ap.error("--if-stale 与 --limit 互斥(抽样表不可当作新鲜快照)")
49
+ cg = MdCG(a.root)
50
+ nodes = cg.index.get("nodes") or {}
51
+ if a.stats:
52
+ st = postings.stats(a.root, nodes)
53
+ print(json.dumps({"terms": st.get("terms"), "postings": st.get("postings"),
54
+ "stale_reason": st.get("stale_reason"),
55
+ "meta": _brief(st.get("meta"))}, ensure_ascii=False))
56
+ return 0
57
+ if a.if_stale:
58
+ sr = postings.stale_reason(a.root, nodes)
59
+ if not sr:
60
+ print(json.dumps({"rebuilt": False, "reason": "fresh"}, ensure_ascii=False))
61
+ return 0
62
+ st = postings.build(cg)
63
+ print(json.dumps(_brief(dict(st, rebuilt_from=sr)), ensure_ascii=False))
64
+ return 0
65
+ st = postings.build(cg, limit=a.limit)
66
+ print(json.dumps(_brief(st), ensure_ascii=False))
67
+ return 0
68
+
69
+
70
+ if __name__ == "__main__":
71
+ if hasattr(sys.stdout, "reconfigure"):
72
+ sys.stdout.reconfigure(encoding="utf-8")
73
+ sys.exit(main())