@furongjun1999/dsh-memory 0.4.11 → 0.5.1

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 (580) hide show
  1. package/README.md +552 -465
  2. package/codebuddy/CODEBUDDY.md +11 -3
  3. package/codebuddy/README.md +92 -90
  4. package/codebuddy/mcp.json +27 -27
  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 -169
  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 -144
  7. package/docs/README.md +143 -111
  8. package/docs/discipline/harnesses.yaml +244 -226
  9. package/docs/discipline/templates/full.md.tmpl +61 -61
  10. package/docs/discipline/templates/rules.mdc.tmpl +68 -0
  11. package/docs/discipline/templates/skill.md.tmpl +23 -23
  12. package/docs/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 +299 -299
  13. package/docs/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 +239 -239
  14. package/docs/eval/bench_lingshu_self/bench_self.py +140 -0
  15. package/docs/eval/bench_lingshu_self/self_bench_result.json +404 -0
  16. package/docs/eval/bench_lingshu_self//347/201/265/346/236/242/350/207/252/345/272/223/347/253/257/345/210/260/347/253/257/346/243/200/347/264/242/345/256/236/346/265/213_v1.0.md +38 -0
  17. package/docs/eval//344/270/215/345/217/257/351/235/240/346/200/247/350/220/275/345/234/260_P0_v1.0.md +185 -0
  18. 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 +174 -174
  19. package/docs/eval//346/225/205/351/232/234/346/263/250/345/205/245/345/256/236/346/265/213_v1.0.md +422 -0
  20. 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 +223 -223
  21. package/docs/eval//347/253/257/345/210/260/347/253/257LoCoMoQA/345/220/214/345/217/243/345/276/204/345/257/271/347/205/247_v1.0.md +100 -0
  22. package/docs/eval//347/253/257/345/210/260/347/253/257/345/271/262/346/211/260/346/261/240/350/257/204/346/265/213_/347/241/256/345/256/232/346/200/247/350/243/201/345/206/263vsLLM_judge_v1.1.md +197 -0
  23. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v1.md +156 -0
  24. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v10.md +210 -0
  25. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v11.md +227 -0
  26. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v12.md +203 -0
  27. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v13.md +233 -0
  28. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v14.md +191 -0
  29. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v15.md +213 -0
  30. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v16.md +214 -0
  31. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v17.md +199 -0
  32. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v2.md +156 -0
  33. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v3.md +152 -0
  34. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v4.md +128 -0
  35. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v5.md +114 -0
  36. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v6.md +192 -0
  37. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v7.md +187 -0
  38. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v8.md +207 -0
  39. package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v9.md +203 -0
  40. package/docs/{mdcg → hive}//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 +165 -160
  41. package/docs/hive//344/273/244/347/211/214/350/257/255/344/271/211/344/277/256/346/255/243_/344/273/262/350/243/201/344/275/215_v0.1.md +76 -0
  42. package/docs/{mdcg → hive}//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 -236
  43. package/docs/hive//345/256/211/345/205/250/345/256/241/350/256/241/345/256/236/351/224/232_v0.1.md +202 -0
  44. 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 -43
  45. package/docs/hive//346/243/200/347/264/242/347/256/227/346/263/225/345/217/243/345/276/204/345/257/271/347/205/247_v0.1.md +85 -0
  46. 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 -102
  47. package/docs/hive//350/234/202/345/267/242M6_ingest/345/256/236/346/226/275/350/256/241/345/210/222_v0.1.md +47 -0
  48. 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 +519 -503
  49. 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 +85 -85
  50. package/docs/hive//350/234/202/345/267/242/350/256/276/350/256/241_/347/220/206/350/256/272/345/257/271/351/275/220_v0.1.md +191 -0
  51. package/docs/hive//350/234/202/345/267/242/350/277/255/344/273/243_/345/256/217/350/247/202/344/270/216/347/276/244/344/275/223/350/260/203/345/272/246_v0.1.md +90 -0
  52. package/docs/images/lingshu-moonlight-covenant-poster-preview.jpg +0 -0
  53. package/docs/images/lingshu-moonlight-covenant-poster.png +0 -0
  54. package/docs/mdcg/D_meta_/345/267/245/347/250/213/345/214/226/346/226/271/346/241/210_v0.2.md +216 -216
  55. package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +646 -646
  56. package/docs/mdcg/lingshu_tutorial.html +14449 -14449
  57. package/docs/mdcg/release_v0.4.11.md +49 -0
  58. package/docs/mdcg/release_v0.4.5.md +55 -55
  59. package/docs/mdcg/tool_table_v0.3.0.md +117 -117
  60. 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 -600
  61. 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 +40 -40
  62. 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 +275 -275
  63. package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +54 -0
  64. 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 +130 -130
  65. 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 +278 -278
  66. 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 -172
  67. package/docs/mdcg//347/274/272/345/217/243/345/215/225_P0/346/224/266/345/217/243_v0.1.md +270 -270
  68. 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 +491 -491
  69. 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 +340 -340
  70. 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 +588 -588
  71. 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 -176
  72. 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 +81 -81
  73. package/docs/swarm//350/234/202/347/276/244/344/272/222/350/201/224_v0.1.md +704 -704
  74. 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 -242
  75. package/docs/theory//344/270/215/345/217/257/351/235/240/345/256/232/347/220/206/344/270/216/345/244/261/346/225/210/344/274/230/345/205/210/346/241/206/346/236/266_v0.3.md +365 -0
  76. 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 -129
  77. 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 -134
  78. package/docs/theory//346/231/272/350/203/275/350/256/2723.4.md +5260 -5260
  79. 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 -145
  80. 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 +144 -144
  81. 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 +198 -198
  82. 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 -221
  83. 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 -237
  84. package/docs//344/270/215/345/217/257/351/235/240/346/200/247/347/220/206/350/256/272_v0.1.md +343 -0
  85. package/docs//345/217/221/345/270/203/344/273/266/345/233/236/346/272/257/350/257/264/346/230/216_v0.1.md +82 -82
  86. 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 +28 -2
  87. package/dsh/README.md +82 -82
  88. package/dsh/cordis.yml.example +139 -139
  89. package/dsh/update-lingshu.bat +11 -11
  90. package/lib/bridge.d.ts +9 -0
  91. package/lib/bridge.js +35 -0
  92. package/lib/hooks.js +36 -2
  93. package/lib/index.js +7 -1
  94. package/lib/lib/roleplay_web.js +116 -29
  95. package/lib/lib/token_store.d.ts +7 -1
  96. package/lib/lib/token_store.js +12 -3
  97. package/md_cg/__init__.py +7 -7
  98. package/md_cg/audit.py +379 -368
  99. package/md_cg/autonomy.py +287 -287
  100. package/md_cg/backfill.py +1328 -1327
  101. package/md_cg/backfill_bigdomain.py +34 -34
  102. package/md_cg/backfill_bucket_zh.py +35 -0
  103. package/md_cg/bench6_arms.py +410 -410
  104. package/md_cg/bench6_common.py +230 -230
  105. package/md_cg/bench6_competitors.py +212 -212
  106. package/md_cg/bench_axis_domain.py +257 -257
  107. package/md_cg/bench_blind_comp.py +308 -308
  108. package/md_cg/bench_e2e_judge.py +532 -0
  109. package/md_cg/bench_e2e_locomo_qa.py +368 -0
  110. package/md_cg/bench_e2e_qa.py +256 -0
  111. package/md_cg/bench_en_atoms_public.py +230 -230
  112. package/md_cg/bench_governance.py +348 -348
  113. package/md_cg/bench_lme_zh.py +410 -410
  114. package/md_cg/bench_locomo.py +121 -121
  115. package/md_cg/bench_locomo_zh.py +450 -450
  116. package/md_cg/bench_locomo_zh_public.py +147 -147
  117. package/md_cg/bench_longmem.py +112 -112
  118. package/md_cg/bench_membench.py +632 -632
  119. package/md_cg/bench_p0.py +149 -149
  120. package/md_cg/bench_progressive.py +287 -287
  121. package/md_cg/bench_role_views.py +238 -238
  122. package/md_cg/bench_task_ab.py +243 -243
  123. package/md_cg/bench_task_ab_llm.py +408 -408
  124. package/md_cg/bench_unified_en.py +204 -204
  125. package/md_cg/bench_zh_mad.py +601 -601
  126. package/md_cg/blindspot_tickets.py +123 -123
  127. package/md_cg/branches.py +301 -285
  128. package/md_cg/build_postings.py +73 -73
  129. package/md_cg/ccgc.py +1006 -948
  130. package/md_cg/census.py +132 -132
  131. package/md_cg/chain.py +315 -300
  132. package/md_cg/codeindex.py +531 -531
  133. package/md_cg/coldverify.py +292 -292
  134. package/md_cg/comment_gate.py +337 -337
  135. package/md_cg/cond_compose.py +190 -190
  136. package/md_cg/cond_facts.py +154 -154
  137. package/md_cg/cond_template.json +106 -106
  138. package/md_cg/condition_anchor.py +142 -142
  139. package/md_cg/conformance.py +726 -726
  140. package/md_cg/consistency.py +717 -717
  141. package/md_cg/consolidate.py +1537 -1439
  142. package/md_cg/corpus.py +110 -110
  143. package/md_cg/crosscheck.py +1098 -1097
  144. package/md_cg/crypto.py +3 -1
  145. package/md_cg/d_meta.py +310 -310
  146. package/md_cg/datapath.py +78 -18
  147. package/md_cg/docindex.py +473 -473
  148. package/md_cg/eval_common.py +575 -575
  149. package/md_cg/evidence.py +4 -2
  150. package/md_cg/evolution.py +477 -477
  151. package/md_cg/export.py +222 -220
  152. package/md_cg/forgetting.py +581 -581
  153. package/md_cg/fsutil.py +377 -329
  154. package/md_cg/hotcache.py +48 -7
  155. package/md_cg/hyperedge.py +251 -251
  156. package/md_cg/identity.py +390 -390
  157. package/md_cg/insight.py +500 -500
  158. package/md_cg/interop.py +338 -0
  159. package/md_cg/judgment_manifest.py +177 -0
  160. package/md_cg/lexicon/build_cedict_en_zh.py +329 -329
  161. package/md_cg/lexicon/build_standard_en.py +171 -171
  162. package/md_cg/lexicon/expand_en_zh.py +211 -211
  163. package/md_cg/lifecycle.py +272 -272
  164. package/md_cg/linkref.py +280 -280
  165. package/md_cg/links.py +140 -107
  166. package/md_cg/mcp_server.py +403 -55
  167. package/md_cg/md_whitebox.py +345 -345
  168. package/md_cg/mdcg.py +783 -233
  169. package/md_cg/mdcos.py +500 -70
  170. package/md_cg/metacognition.py +591 -591
  171. package/md_cg/migrate.py +119 -119
  172. package/md_cg/migrate_aeis.py +221 -221
  173. package/md_cg/migrate_roleplay.py +293 -293
  174. package/md_cg/migrate_wisdom_graph.py +360 -360
  175. package/md_cg/mreview/__init__.py +25 -25
  176. package/md_cg/mreview/__main__.py +110 -110
  177. package/md_cg/mreview/bundle.py +178 -178
  178. package/md_cg/mreview/candidates.py +262 -262
  179. package/md_cg/mreview/govern.py +694 -693
  180. package/md_cg/mreview/locate.py +939 -939
  181. package/md_cg/mreview/pipeline.py +728 -728
  182. package/md_cg/mreview/rules/duplication.json +21 -21
  183. package/md_cg/mreview/rules/field_coverage.json +54 -54
  184. package/md_cg/mreview/rules/source_license.json +21 -21
  185. package/md_cg/mreview/rules/template_flow.json +21 -21
  186. package/md_cg/mreview/ruleset.py +252 -252
  187. package/md_cg/nodefile.py +575 -575
  188. package/md_cg/pooling.py +484 -472
  189. package/md_cg/postings.py +300 -298
  190. package/md_cg/predict.py +1100 -1100
  191. package/md_cg/progressive.py +123 -123
  192. package/md_cg/protect.py +272 -272
  193. package/md_cg/protocol/md_cg_gate.proto +33 -33
  194. package/md_cg/protocol.py +372 -372
  195. package/md_cg/provenance.py +582 -582
  196. package/md_cg/reach.py +453 -453
  197. package/md_cg/readcache.py +143 -0
  198. package/md_cg/reconcile.py +228 -0
  199. package/md_cg/refindex.py +833 -833
  200. package/md_cg/refine.py +604 -604
  201. package/md_cg/review_cli.py +170 -0
  202. package/md_cg/roleviews.py +89 -89
  203. package/md_cg/routing.py +393 -365
  204. package/md_cg/run_tests.py +211 -0
  205. package/md_cg/scrub.py +13 -3
  206. package/md_cg/security.py +128 -18
  207. package/md_cg/self_state.py +1029 -1029
  208. package/md_cg/selfreport.py +152 -151
  209. package/md_cg/semantic/__init__.py +10 -10
  210. package/md_cg/semantic/canonical.py +122 -122
  211. package/md_cg/semantic/en_normalizer.py +364 -364
  212. package/md_cg/semantic/en_zh_map.json +28694 -0
  213. package/md_cg/semantic/export_en_zh_map.py +64 -0
  214. package/md_cg/semantic/unify.py +45 -0
  215. package/md_cg/semantic/zh_en_atoms.py +139 -139
  216. package/md_cg/signer.py +7 -4
  217. package/md_cg/sources.py +816 -582
  218. package/md_cg/statushdr.py +179 -179
  219. package/md_cg/stg.py +54 -37
  220. package/md_cg/subgraph.py +729 -729
  221. package/md_cg/sustain.py +35 -5
  222. package/md_cg/tasks.py +470 -470
  223. package/md_cg/test_access_hints.py +147 -0
  224. package/md_cg/test_action_derive.py +203 -203
  225. package/md_cg/test_audit_rotate.py +270 -270
  226. package/md_cg/test_autonomy.py +143 -143
  227. package/md_cg/test_bench_governance.py +102 -102
  228. package/md_cg/test_blindspot_tickets.py +166 -166
  229. package/md_cg/test_branch_discard_tombstone.py +136 -0
  230. package/md_cg/test_branches.py +13 -3
  231. package/md_cg/test_ccg_perturb.py +184 -184
  232. package/md_cg/test_ccgc.py +433 -433
  233. package/md_cg/test_census_prune.py +81 -81
  234. package/md_cg/test_chain_read_isolate.py +168 -0
  235. package/md_cg/test_cond_compose_anchors.py +76 -76
  236. package/md_cg/test_cond_match.py +165 -165
  237. package/md_cg/test_condition_anchor.py +81 -81
  238. package/md_cg/test_d_meta.py +412 -412
  239. package/md_cg/test_datapath_device_name.py +203 -0
  240. package/md_cg/test_datapath_root.py +199 -199
  241. package/md_cg/test_emit_negtail_cache.py +156 -0
  242. package/md_cg/test_en_pipeline.py +22 -2
  243. package/md_cg/test_gain_gate.py +212 -212
  244. package/md_cg/test_govern_directread.py +421 -0
  245. package/md_cg/test_health_scale.py +173 -173
  246. package/md_cg/test_hive_ingest.py +285 -0
  247. package/md_cg/test_hot_cold.py +215 -215
  248. package/md_cg/test_hyperedge.py +245 -245
  249. package/md_cg/test_i26_empty_first_write.py +116 -0
  250. package/md_cg/test_i27_e041_identity.py +128 -0
  251. package/md_cg/test_i28_hotcache_prodpath.py +122 -0
  252. package/md_cg/test_i32_hotcache_env_key.py +218 -0
  253. package/md_cg/test_identity_attribution.py +96 -15
  254. package/md_cg/test_index_durability.py +17 -3
  255. package/md_cg/test_interop.py +95 -0
  256. package/md_cg/test_interop_judgment.py +228 -0
  257. package/md_cg/test_issue39_utf8_stdio.py +273 -0
  258. package/md_cg/test_lifecycle.py +309 -309
  259. package/md_cg/test_linkref.py +306 -306
  260. package/md_cg/test_links_concurrent_write.py +188 -0
  261. package/md_cg/test_lock.py +43 -43
  262. package/md_cg/test_md_access_parity.py +255 -255
  263. package/md_cg/test_md_writepath.py +345 -345
  264. package/md_cg/test_mdstore_search_parity.py +160 -0
  265. package/md_cg/test_merge_upsert.py +168 -0
  266. package/md_cg/test_mr_m2.py +587 -587
  267. package/md_cg/test_mr_m3.py +710 -710
  268. package/md_cg/test_mr_m4.py +485 -485
  269. package/md_cg/test_n123_derive_expiry_chain.py +205 -0
  270. package/md_cg/test_n130_verify_falsified_protect.py +185 -0
  271. package/md_cg/test_n131_merge_gate.py +205 -0
  272. package/md_cg/test_p0.py +250 -250
  273. package/md_cg/test_p1.py +316 -316
  274. package/md_cg/test_p10_identity.py +173 -173
  275. package/md_cg/test_p11_consistency.py +233 -233
  276. package/md_cg/test_p12_metacognition.py +212 -212
  277. package/md_cg/test_p13_encryption.py +241 -241
  278. package/md_cg/test_p14_sustain.py +249 -249
  279. package/md_cg/test_p15_scrub.py +280 -280
  280. package/md_cg/test_p16_self_state.py +301 -301
  281. package/md_cg/test_p17_predict.py +354 -354
  282. package/md_cg/test_p18_whitebox.py +171 -171
  283. package/md_cg/test_p19_migrate_roleplay.py +149 -149
  284. package/md_cg/test_p1x_ref_root.py +160 -0
  285. package/md_cg/test_p20_evolution.py +315 -315
  286. package/md_cg/test_p21_tokens.py +293 -270
  287. package/md_cg/test_p22_theory.py +175 -175
  288. package/md_cg/test_p23_links.py +311 -311
  289. package/md_cg/test_p24_evidence.py +227 -227
  290. package/md_cg/test_p25_weights.py +156 -156
  291. package/md_cg/test_p26_refindex.py +416 -416
  292. package/md_cg/test_p27_docindex.py +16 -7
  293. package/md_cg/test_p28_refcheck.py +305 -305
  294. package/md_cg/test_p29_session_ingest_export.py +354 -333
  295. package/md_cg/test_p2_mcp.py +3 -0
  296. package/md_cg/test_p3.py +11 -2
  297. package/md_cg/test_p30_maintain.py +330 -330
  298. package/md_cg/test_p31_insight.py +534 -534
  299. package/md_cg/test_p32_backfill.py +7 -1
  300. package/md_cg/test_p33_ccg_wiring.py +293 -293
  301. package/md_cg/test_p34_crosscheck.py +331 -331
  302. package/md_cg/test_p35_conditioned_claim.py +252 -252
  303. package/md_cg/test_p36_kp_align.py +230 -230
  304. package/md_cg/test_p37_condition_space.py +248 -248
  305. package/md_cg/test_p38_concurrent_flush.py +102 -0
  306. package/md_cg/test_p38_contextualize.py +273 -273
  307. package/md_cg/test_p39_verify_flow.py +153 -0
  308. package/md_cg/test_p39_vision_evidence.py +369 -369
  309. package/md_cg/test_p40_refine_worklist.py +241 -241
  310. package/md_cg/test_p41_evolve_patrol.py +224 -224
  311. package/md_cg/test_p42_provenance.py +269 -269
  312. package/md_cg/test_p43_pooling.py +412 -398
  313. package/md_cg/test_p44_md_whitebox.py +231 -231
  314. package/md_cg/test_p45_session_identity.py +219 -219
  315. package/md_cg/test_p46_unit_scope.py +272 -272
  316. package/md_cg/test_p47_session_view.py +316 -0
  317. package/md_cg/test_p4_fuzzy.py +223 -223
  318. package/md_cg/test_p5_semantic.py +226 -226
  319. package/md_cg/test_p6_consolidate.py +440 -387
  320. package/md_cg/test_p7_goals_recent.py +202 -202
  321. package/md_cg/test_p8_subgraph_chain.py +200 -200
  322. package/md_cg/test_p9_forget_protect.py +231 -231
  323. package/md_cg/test_predict_beta.py +135 -135
  324. package/md_cg/test_preflight_failclosed.py +100 -100
  325. package/md_cg/test_progressive.py +146 -146
  326. package/md_cg/test_propose_tail_index.py +157 -0
  327. package/md_cg/test_protocol.py +243 -243
  328. package/md_cg/test_reach.py +378 -378
  329. package/md_cg/test_reach_keys.py +201 -201
  330. package/md_cg/test_read_clip.py +141 -141
  331. package/md_cg/test_read_scope_b27.py +277 -0
  332. package/md_cg/test_readcache_default_on.py +168 -0
  333. package/md_cg/test_readcache_precise_inval.py +270 -0
  334. package/md_cg/test_readcache_prodpath.py +203 -0
  335. package/md_cg/test_reconcile_v0.py +294 -0
  336. package/md_cg/test_retr_gates_prodpath.py +140 -0
  337. package/md_cg/test_retr_s1.py +344 -340
  338. package/md_cg/test_retr_s1b.py +276 -209
  339. package/md_cg/test_retr_s3.py +194 -194
  340. package/md_cg/test_retr_s4.py +163 -163
  341. package/md_cg/test_retr_s5.py +200 -200
  342. package/md_cg/test_retr_s6.py +157 -157
  343. package/md_cg/test_retr_s7.py +392 -384
  344. package/md_cg/test_retr_s8_time.py +369 -316
  345. package/md_cg/test_retr_s9_edges.py +286 -286
  346. package/md_cg/test_retr_s9_entity_ctx.py +9 -3
  347. package/md_cg/test_retr_score_once.py +208 -0
  348. package/md_cg/test_review_conformance.py +367 -367
  349. package/md_cg/test_review_onepass.py +170 -0
  350. package/md_cg/test_role_views.py +354 -354
  351. package/md_cg/test_rrf_graph_seed_cache.py +154 -0
  352. package/md_cg/test_security_audit.py +155 -0
  353. package/md_cg/test_security_audit_b26.py +161 -0
  354. package/md_cg/test_security_audit_v21.py +250 -0
  355. package/md_cg/test_sem_noise.py +242 -242
  356. package/md_cg/test_semantic_canonical.py +16 -2
  357. package/md_cg/test_session_isolation.py +168 -0
  358. package/md_cg/test_snapshot_autoclose.py +187 -0
  359. package/md_cg/test_subproc_encoding.py +192 -192
  360. package/md_cg/test_sustain_mutual.py +153 -153
  361. package/md_cg/test_tail_watermark_race.py +208 -0
  362. package/md_cg/test_tasks.py +409 -409
  363. package/md_cg/test_tenant_env_override_warn.py +139 -0
  364. package/md_cg/test_tenant_registry_corrupt_warn.py +151 -0
  365. package/md_cg/test_tool_face.py +189 -189
  366. package/md_cg/test_transfer.py +180 -180
  367. package/md_cg/test_trust.py +361 -361
  368. package/md_cg/test_twophase.py +286 -286
  369. package/md_cg/test_v14_fixes.py +38 -20
  370. package/md_cg/test_validity_filter.py +280 -280
  371. package/md_cg/test_verify_answer.py +138 -138
  372. package/md_cg/test_verify_dirty_reconcile.py +157 -0
  373. package/md_cg/test_wisdom_md_store.py +292 -292
  374. package/md_cg/test_writelimit.py +197 -197
  375. package/md_cg/test_writepipe.py +214 -214
  376. package/md_cg/theory.py +6 -3
  377. package/md_cg/tokens.py +85 -14
  378. package/md_cg/tool_face.py +260 -260
  379. package/md_cg/trust.py +986 -950
  380. package/md_cg/twophase.py +231 -231
  381. package/md_cg/units.py +668 -667
  382. package/md_cg/vision_evidence.py +667 -666
  383. package/md_cg/weights.py +624 -624
  384. package/md_cg/whitebox.py +527 -527
  385. package/md_cg/whitebox_kb/__init__.py +37 -37
  386. package/md_cg/whitebox_kb/aeis_core/__init__.py +42 -42
  387. package/md_cg/whitebox_kb/aeis_core/semantic.py +280 -280
  388. package/md_cg/whitebox_kb/aeis_core/textutil.py +13 -13
  389. package/md_cg/whitebox_kb/engine.py +310 -310
  390. package/md_cg/whitebox_kb/seed_knowledge//346/231/272/350/203/275/350/256/2723.4.md +5260 -5260
  391. package/md_cg/whitebox_kb/wisdom/browser_units.py +2631 -2631
  392. package/md_cg/whitebox_kb/wisdom/causal_discover.py +432 -432
  393. package/md_cg/whitebox_kb/wisdom/chat_engine.py +1506 -1506
  394. package/md_cg/whitebox_kb/wisdom/compiler_code_units.py +3033 -3033
  395. package/md_cg/whitebox_kb/wisdom/condition_algebra.py +112 -112
  396. package/md_cg/whitebox_kb/wisdom/condition_frame.py +315 -315
  397. package/md_cg/whitebox_kb/wisdom/condition_kb.py +108 -108
  398. package/md_cg/whitebox_kb/wisdom/conflict_map.json +4445 -4445
  399. package/md_cg/whitebox_kb/wisdom/core/lexer.py +512 -512
  400. package/md_cg/whitebox_kb/wisdom/core/name_checker.py +1023 -1023
  401. package/md_cg/whitebox_kb/wisdom/cspmn.py +258 -258
  402. package/md_cg/whitebox_kb/wisdom/csre.py +264 -264
  403. package/md_cg/whitebox_kb/wisdom/danmaku_audit.py +252 -252
  404. package/md_cg/whitebox_kb/wisdom/distilled_condition_units.json +6417 -6417
  405. package/md_cg/whitebox_kb/wisdom/docs/WB-EVAL-20260902b.json +1950 -1950
  406. package/md_cg/whitebox_kb/wisdom/docs/WB-EVAL-20260902c.json +1296 -1296
  407. package/md_cg/whitebox_kb/wisdom/docs/whitebox_capability_graph_demo.json +59 -59
  408. package/md_cg/whitebox_kb/wisdom/graph_db_units.py +3089 -3089
  409. package/md_cg/whitebox_kb/wisdom/knowledge_points.py +318 -318
  410. package/md_cg/whitebox_kb/wisdom/md_access.py +470 -470
  411. package/md_cg/whitebox_kb/wisdom/md_store.py +276 -251
  412. package/md_cg/whitebox_kb/wisdom/migrate_wisdom.py +476 -476
  413. package/md_cg/whitebox_kb/wisdom/multilang_ir.py +128 -124
  414. package/md_cg/whitebox_kb/wisdom/navigate.py +248 -248
  415. package/md_cg/whitebox_kb/wisdom/neural_retrieve.py +224 -224
  416. package/md_cg/whitebox_kb/wisdom/os_units.py +2735 -2735
  417. package/md_cg/whitebox_kb/wisdom/pattern_separation.py +376 -376
  418. package/md_cg/whitebox_kb/wisdom/prereq_map.json +364 -364
  419. package/md_cg/whitebox_kb/wisdom/python_code_units.py +2766 -2766
  420. package/md_cg/whitebox_kb/wisdom/role_solidified.json +7 -7
  421. package/md_cg/whitebox_kb/wisdom/route_memory.py +244 -244
  422. package/md_cg/whitebox_kb/wisdom/scene_reconstruction.py +148 -148
  423. package/md_cg/whitebox_kb/wisdom/snr_report.json +40 -40
  424. package/md_cg/whitebox_kb/wisdom/test_code_compose_domains.py +7541 -7541
  425. package/md_cg/whitebox_kb/wisdom/test_compiler_self_bootstrap.py +354 -354
  426. package/md_cg/whitebox_kb/wisdom/test_ecosystem_assembly.py +158 -158
  427. package/md_cg/whitebox_kb/wisdom/test_ecosystem_demos.py +193 -193
  428. package/md_cg/whitebox_kb/wisdom/test_graph_db.py +292 -292
  429. package/md_cg/whitebox_kb/wisdom/test_python_self_bootstrap.py +160 -160
  430. package/md_cg/whitebox_kb/wisdom/trigger_words_index.json +4366 -4366
  431. package/md_cg/whitebox_kb/wisdom/verifier.py +1297 -1297
  432. package/md_cg/writelimit.py +356 -356
  433. package/md_cg/writepipe.py +20 -8
  434. package/package.json +101 -96
  435. package/skills/plugin.json +54 -54
  436. package/skills/skills/designer-perspective/SKILL.md +158 -158
  437. package/skills/skills/designer-perspective/references/01-observation-position.md +66 -66
  438. package/skills/skills/designer-perspective/references/02-structure-recognition.md +62 -62
  439. package/skills/skills/designer-perspective/references/03-direction-judgment.md +55 -55
  440. package/skills/skills/designer-perspective/references/04-qualification-verdict.md +72 -72
  441. package/skills/skills/designer-perspective/references/05-condition-attribution.md +74 -74
  442. package/skills/skills/designer-perspective/scripts/designer.py +545 -545
  443. package/skills/skills/designer-perspective/tests/cases.jsonl +17 -17
  444. package/skills/skills/designer-perspective/tests/selftest.py +61 -61
  445. package/skills/skills/lingshu-browser/SKILL.md +60 -60
  446. package/skills/skills/lingshu-compiler/SKILL.md +56 -56
  447. package/skills/skills/lingshu-compiler/units/analyze-type-infer/SKILL.md +45 -45
  448. package/skills/skills/lingshu-compiler/units/check-name-real/SKILL.md +45 -45
  449. package/skills/skills/lingshu-compiler/units/compile-assign/SKILL.md +45 -45
  450. package/skills/skills/lingshu-compiler/units/compile-expr-tree/SKILL.md +45 -45
  451. package/skills/skills/lingshu-compiler/units/compile-full-pipeline/SKILL.md +45 -45
  452. package/skills/skills/lingshu-compiler/units/compile-func-def/SKILL.md +45 -45
  453. package/skills/skills/lingshu-compiler/units/compile-if-then/SKILL.md +45 -45
  454. package/skills/skills/lingshu-compiler/units/compile-logic-expr/SKILL.md +45 -45
  455. package/skills/skills/lingshu-compiler/units/compile-recursive/SKILL.md +45 -45
  456. package/skills/skills/lingshu-compiler/units/compile-scope/SKILL.md +45 -45
  457. package/skills/skills/lingshu-compiler/units/compile-type-check/SKILL.md +45 -45
  458. package/skills/skills/lingshu-compiler/units/compile-while/SKILL.md +45 -45
  459. package/skills/skills/lingshu-compiler/units/compiler-0010c4bf/SKILL.md +45 -45
  460. package/skills/skills/lingshu-compiler/units/compiler-0355bffb/SKILL.md +45 -45
  461. package/skills/skills/lingshu-compiler/units/compiler-0361708a/SKILL.md +45 -45
  462. package/skills/skills/lingshu-compiler/units/compiler-054a0414/SKILL.md +45 -45
  463. package/skills/skills/lingshu-compiler/units/compiler-05a1691a/SKILL.md +45 -45
  464. package/skills/skills/lingshu-compiler/units/compiler-05eeed1e/SKILL.md +45 -45
  465. package/skills/skills/lingshu-compiler/units/compiler-0622a1f6/SKILL.md +45 -45
  466. package/skills/skills/lingshu-compiler/units/compiler-08b54217/SKILL.md +45 -45
  467. package/skills/skills/lingshu-compiler/units/compiler-0a62b70c/SKILL.md +45 -45
  468. package/skills/skills/lingshu-compiler/units/compiler-0ab24d00/SKILL.md +45 -45
  469. package/skills/skills/lingshu-compiler/units/compiler-0e093688/SKILL.md +45 -45
  470. package/skills/skills/lingshu-compiler/units/compiler-0e82b966/SKILL.md +45 -45
  471. package/skills/skills/lingshu-compiler/units/compiler-0ee9b9b9/SKILL.md +45 -45
  472. package/skills/skills/lingshu-compiler/units/compiler-0f3787e6/SKILL.md +45 -45
  473. package/skills/skills/lingshu-compiler/units/compiler-1028685f/SKILL.md +45 -45
  474. package/skills/skills/lingshu-compiler/units/compiler-11897630/SKILL.md +45 -45
  475. package/skills/skills/lingshu-compiler/units/compiler-16661b9b/SKILL.md +45 -45
  476. package/skills/skills/lingshu-compiler/units/compiler-1f722303/SKILL.md +45 -45
  477. package/skills/skills/lingshu-compiler/units/compiler-25be1262/SKILL.md +45 -45
  478. package/skills/skills/lingshu-compiler/units/compiler-2a76ba07/SKILL.md +45 -45
  479. package/skills/skills/lingshu-compiler/units/compiler-2dbea54a/SKILL.md +45 -45
  480. package/skills/skills/lingshu-compiler/units/compiler-2df52f16/SKILL.md +45 -45
  481. package/skills/skills/lingshu-compiler/units/compiler-2ec2c9d2/SKILL.md +45 -45
  482. package/skills/skills/lingshu-compiler/units/compiler-2f8c8f39/SKILL.md +45 -45
  483. package/skills/skills/lingshu-compiler/units/compiler-38378ac7/SKILL.md +45 -45
  484. package/skills/skills/lingshu-compiler/units/compiler-39457d2e/SKILL.md +45 -45
  485. package/skills/skills/lingshu-compiler/units/compiler-39fb5926/SKILL.md +45 -45
  486. package/skills/skills/lingshu-compiler/units/compiler-47f4fbfa/SKILL.md +45 -45
  487. package/skills/skills/lingshu-compiler/units/compiler-4a8cd1f1/SKILL.md +45 -45
  488. package/skills/skills/lingshu-compiler/units/compiler-4b230b6b/SKILL.md +45 -45
  489. package/skills/skills/lingshu-compiler/units/compiler-4cbbda95/SKILL.md +45 -45
  490. package/skills/skills/lingshu-compiler/units/compiler-4d5a68ff/SKILL.md +45 -45
  491. package/skills/skills/lingshu-compiler/units/compiler-56dc9bdd/SKILL.md +45 -45
  492. package/skills/skills/lingshu-compiler/units/compiler-57e76ebe/SKILL.md +45 -45
  493. package/skills/skills/lingshu-compiler/units/compiler-61ff016b/SKILL.md +45 -45
  494. package/skills/skills/lingshu-compiler/units/compiler-63eae588/SKILL.md +45 -45
  495. package/skills/skills/lingshu-compiler/units/compiler-64c4224b/SKILL.md +45 -45
  496. package/skills/skills/lingshu-compiler/units/compiler-66377955/SKILL.md +45 -45
  497. package/skills/skills/lingshu-compiler/units/compiler-674ab4f6/SKILL.md +45 -45
  498. package/skills/skills/lingshu-compiler/units/compiler-6af76fd6/SKILL.md +45 -45
  499. package/skills/skills/lingshu-compiler/units/compiler-6d979db2/SKILL.md +45 -45
  500. package/skills/skills/lingshu-compiler/units/compiler-6de326c0/SKILL.md +45 -45
  501. package/skills/skills/lingshu-compiler/units/compiler-6f1c0eea/SKILL.md +45 -45
  502. package/skills/skills/lingshu-compiler/units/compiler-724d6c9b/SKILL.md +45 -45
  503. package/skills/skills/lingshu-compiler/units/compiler-7690177f/SKILL.md +45 -45
  504. package/skills/skills/lingshu-compiler/units/compiler-7b229a7d/SKILL.md +45 -45
  505. package/skills/skills/lingshu-compiler/units/compiler-7f471b3a/SKILL.md +45 -45
  506. package/skills/skills/lingshu-compiler/units/compiler-815cad08/SKILL.md +45 -45
  507. package/skills/skills/lingshu-compiler/units/compiler-83c61634/SKILL.md +45 -45
  508. package/skills/skills/lingshu-compiler/units/compiler-8c798c81/SKILL.md +45 -45
  509. package/skills/skills/lingshu-compiler/units/compiler-8dd747ac/SKILL.md +45 -45
  510. package/skills/skills/lingshu-compiler/units/compiler-90324d0a/SKILL.md +45 -45
  511. package/skills/skills/lingshu-compiler/units/compiler-94b8d72d/SKILL.md +45 -45
  512. package/skills/skills/lingshu-compiler/units/compiler-94f12231/SKILL.md +45 -45
  513. package/skills/skills/lingshu-compiler/units/compiler-95937c16/SKILL.md +45 -45
  514. package/skills/skills/lingshu-compiler/units/compiler-98a5625b/SKILL.md +45 -45
  515. package/skills/skills/lingshu-compiler/units/compiler-98b4c42f/SKILL.md +45 -45
  516. package/skills/skills/lingshu-compiler/units/compiler-98e3894a/SKILL.md +45 -45
  517. package/skills/skills/lingshu-compiler/units/compiler-9bdfe4b8/SKILL.md +45 -45
  518. package/skills/skills/lingshu-compiler/units/compiler-9d9b4e83/SKILL.md +45 -45
  519. package/skills/skills/lingshu-compiler/units/compiler-9f7be5ad/SKILL.md +45 -45
  520. package/skills/skills/lingshu-compiler/units/compiler-a6daf076/SKILL.md +45 -45
  521. package/skills/skills/lingshu-compiler/units/compiler-a7995a0c/SKILL.md +45 -45
  522. package/skills/skills/lingshu-compiler/units/compiler-a8399248/SKILL.md +45 -45
  523. package/skills/skills/lingshu-compiler/units/compiler-aabbd099/SKILL.md +45 -45
  524. package/skills/skills/lingshu-compiler/units/compiler-afe169d8/SKILL.md +45 -45
  525. package/skills/skills/lingshu-compiler/units/compiler-b0678bda/SKILL.md +45 -45
  526. package/skills/skills/lingshu-compiler/units/compiler-b09bd196/SKILL.md +45 -45
  527. package/skills/skills/lingshu-compiler/units/compiler-b1396e23/SKILL.md +45 -45
  528. package/skills/skills/lingshu-compiler/units/compiler-b9b31ce0/SKILL.md +45 -45
  529. package/skills/skills/lingshu-compiler/units/compiler-c10264a7/SKILL.md +45 -45
  530. package/skills/skills/lingshu-compiler/units/compiler-cb1e8e4b/SKILL.md +45 -45
  531. package/skills/skills/lingshu-compiler/units/compiler-ccafd438/SKILL.md +45 -45
  532. package/skills/skills/lingshu-compiler/units/compiler-cda9c262/SKILL.md +45 -45
  533. package/skills/skills/lingshu-compiler/units/compiler-ce648068/SKILL.md +45 -45
  534. package/skills/skills/lingshu-compiler/units/compiler-cf5776a4/SKILL.md +45 -45
  535. package/skills/skills/lingshu-compiler/units/compiler-d974e5d3/SKILL.md +45 -45
  536. package/skills/skills/lingshu-compiler/units/compiler-e3979fd3/SKILL.md +45 -45
  537. package/skills/skills/lingshu-compiler/units/compiler-eb1cf2b5/SKILL.md +45 -45
  538. package/skills/skills/lingshu-compiler/units/compiler-ecb30d5b/SKILL.md +45 -45
  539. package/skills/skills/lingshu-compiler/units/compiler-f8c8b24b/SKILL.md +45 -45
  540. package/skills/skills/lingshu-compiler/units/compiler-f99fedbe/SKILL.md +45 -45
  541. package/skills/skills/lingshu-compiler/units/compiler-fa8ff5f7/SKILL.md +45 -45
  542. package/skills/skills/lingshu-compiler/units/compiler-fe1b058d/SKILL.md +45 -45
  543. package/skills/skills/lingshu-compiler/units/lex-chinese-program/SKILL.md +45 -45
  544. package/skills/skills/lingshu-compiler/units/lex-dao-de-jing/SKILL.md +45 -45
  545. package/skills/skills/lingshu-compiler/units/lex-nine-chapters/SKILL.md +45 -45
  546. package/skills/skills/lingshu-compiler/units/vm-arithmetic/SKILL.md +45 -45
  547. package/skills/skills/lingshu-compiler/units/vm-array-ops/SKILL.md +45 -45
  548. package/skills/skills/lingshu-compiler/units/vm-closure-call/SKILL.md +45 -45
  549. package/skills/skills/lingshu-compiler/units/vm-closure-create/SKILL.md +45 -45
  550. package/skills/skills/lingshu-compiler/units/vm-compare/SKILL.md +45 -45
  551. package/skills/skills/lingshu-compiler/units/vm-cond-jump/SKILL.md +45 -45
  552. package/skills/skills/lingshu-compiler/units/vm-cond-space/SKILL.md +45 -45
  553. package/skills/skills/lingshu-compiler/units/vm-exception/SKILL.md +45 -45
  554. package/skills/skills/lingshu-compiler/units/vm-func-call/SKILL.md +45 -45
  555. package/skills/skills/lingshu-compiler/units/vm-loop-run/SKILL.md +45 -45
  556. package/skills/skills/lingshu-compiler/units/vm-profiling/SKILL.md +45 -45
  557. package/skills/skills/lingshu-compiler/units/vm-refcount/SKILL.md +45 -45
  558. package/skills/skills/lingshu-compiler/units/vm-run-loop/SKILL.md +45 -45
  559. package/skills/skills/lingshu-compiler/units/vm-short-circuit/SKILL.md +45 -45
  560. package/skills/skills/lingshu-compiler/units/vm-stack-guard/SKILL.md +45 -45
  561. package/skills/skills/lingshu-compiler/units/vm-stack-ops/SKILL.md +45 -45
  562. package/skills/skills/lingshu-compiler/units/vm-trust-accum/SKILL.md +45 -45
  563. package/skills/skills/lingshu-graph/SKILL.md +63 -63
  564. package/skills/skills/lingshu-net/SKILL.md +48 -48
  565. package/skills/skills/lingshu-os/SKILL.md +64 -64
  566. package/skills/skills/lingshu-pylang/SKILL.md +71 -71
  567. package/src/bridge.ts +33 -0
  568. package/src/hooks.ts +38 -2
  569. package/src/index.ts +526 -518
  570. package/src/lib/datapath.ts +326 -326
  571. package/src/lib/mdcg_client.ts +413 -413
  572. package/src/lib/mutual.ts +428 -428
  573. package/src/lib/prompt_safety.ts +62 -62
  574. package/src/lib/python_path.ts +71 -71
  575. package/src/lib/roleplay_web.ts +116 -29
  576. package/src/lib/token_store.ts +13 -3
  577. package/src/tools.ts +212 -212
  578. package/zcode/AGENTS.md +11 -3
  579. package/zcode/README.md +41 -41
  580. /package/docs/{mdcg → hive}//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" +0 -0
@@ -1,409 +1,409 @@
1
- # -*- coding: utf-8 -*-
2
- """结构层任务实体(md_cg/tasks.py)验收矩阵(2026-09-16)。
3
-
4
- 蓝图=消除 AI 失忆四症状,断言按症状逐条对位:
5
-
6
- ① 忘记已实现的工程 → H 组:session_tasks / session_recall 任务段,
7
- 且**不按 session 过滤**(工程台账跨会话可见,这正是失忆的解)
8
- ② 计划与实际不符 → F 组:计划每轮覆盖更新 + 「计划变更」节逐轮累积
9
- ③ 缺核验 → E 组:done 时结果必填闸(缺一不收),拒收后**盘上内容逐字节不变**
10
- ④ 换表述即新任务 → A/C/I 组:身份=语义 slug(非内容哈希);同 slug 幂等更新
11
- 不新增节点;同族只提示、不自动合并
12
-
13
- 另含 MCP 面对位(L 组:action 推导不吞写意图 / schema 参数声明 / 缺省 list 冒烟 /
14
- 未知 action fail-closed)与边界(J 组:串号防护、检索面、反向关联;M 组:权限闸)。
15
- 脚本式 assert + 退出码,风格与 test_branches.py / test_action_derive.py 一致。
16
- """
17
-
18
- import os
19
- import re
20
- import sys
21
- import shutil
22
- import inspect
23
- import tempfile
24
- import hashlib
25
-
26
- _HERE = os.path.dirname(os.path.abspath(__file__))
27
- _REPO = os.path.dirname(_HERE)
28
- if _REPO not in sys.path:
29
- sys.path.insert(0, _REPO)
30
-
31
- try:
32
- sys.stdout.reconfigure(encoding="utf-8", errors="replace")
33
- except Exception:
34
- pass
35
-
36
- from md_cg import mcp_server as M
37
- from md_cg import tasks as T
38
- from md_cg import tokens as TK
39
- from md_cg.mdcos import MdCGSecure
40
- from md_cg.security import Principal, AccessDenied
41
-
42
- # 语料命名(互不串扰,各症状用独立任务名)
43
- NAME = "记忆失忆修复-工程"
44
- NAME2 = "任务实体-done闸探针"
45
- NAME3 = "mcp面-任务探针"
46
- NAME4 = "任务-未开先done"
47
- NAME5 = "越权任务"
48
-
49
- _fails = []
50
- _n = [0]
51
-
52
-
53
- def check(name, cond, detail=None):
54
- _n[0] += 1
55
- if cond:
56
- print(" ok %s" % name)
57
- else:
58
- print("FAIL %s %r" % (name, detail))
59
- _fails.append(name)
60
-
61
-
62
- def _raises(fn):
63
- try:
64
- fn()
65
- except Exception as e: # noqa: BLE001 —— 测试需拿到任何异常作证据
66
- return e
67
- return None
68
-
69
-
70
- def _mk_cg(root, **kw):
71
- p = Principal(actor="task_test", role="designer", can_write=True, can_admin=True,
72
- ops_allow=["*"], layers_allow=["*"], **kw)
73
- return MdCGSecure(root, principal=p)
74
-
75
-
76
- def _task_nodes(cg):
77
- return sorted(n for n in cg.index["nodes"] if n.startswith(T.TASK_PREFIX))
78
-
79
-
80
- def _hits(cg, q, **kw):
81
- res, _meta = cg.search(q, **kw)
82
- return [h[0].get("id") for h in res]
83
-
84
-
85
- def main():
86
- tmp = tempfile.mkdtemp(prefix="mdcg_tasks_")
87
- try:
88
- _root = os.path.join(tmp, "root")
89
- cg = _mk_cg(_root)
90
- nid = T.task_node_id(NAME)
91
-
92
- # ---------------- A. 身份判据=语义 slug(症状④ 的根) ----------------
93
- print("\n[A] 身份判据:语义 slug,非内容哈希")
94
- check("A1 中文名原样保留(语义身份可读)",
95
- T.slugify(NAME) == NAME, T.slugify(NAME))
96
- check("A2 路径分隔符折叠(防目录穿越)",
97
- T.slugify("a/b\\c") == "a-b-c", T.slugify("a/b\\c"))
98
- _trav = T.slugify("../../etc/passwd")
99
- check("A3 `..` 与 `/` 全部折叠,不留穿越形态",
100
- ".." not in _trav and "/" not in _trav and "\\" not in _trav, _trav)
101
- check("A4 空白/纯符号名拒收(无身份不建卡)",
102
- T.task_node_id(" ") is None or T.slugify(" ") == "", T.slugify(" "))
103
- check("A4b 纯符号名 slug 为空", T.slugify("!!!") == "", T.slugify("!!!"))
104
- check("A5 已带前缀不重复叠(task_x → task_x)",
105
- T.task_node_id("task_x") == "task_x" == T.task_node_id("x"),
106
- (T.task_node_id("task_x"), T.task_node_id("x")))
107
- check("A6 超长名截断(≥64 上限护栏)",
108
- len(T.task_node_id("a" * 200)) <= len(T.TASK_PREFIX) + 64,
109
- len(T.task_node_id("a" * 200)))
110
- _o = T.upsert(cg, "任务 名(一)", plan="探针")
111
- check("A7 归一化透明(原名与 slug 同返,不静默改名)",
112
- _o.get("ok") and _o.get("slug_normalized") == "任务-名-一"
113
- and _o.get("node_id") == "task_任务-名-一", _o)
114
-
115
- # ---------------- B. 创建与读回(结构层定位) ----------------
116
- print("\n[B] 创建与读回:structural 层一等节点")
117
- r = T.upsert(cg, NAME, goal="消除 AI 四症状失忆",
118
- plan="1) 建 tasks.py 2) 接 MCP 3) 会话段 4) 测试",
119
- acceptance="四症状逐条有对位断言", boundary="不动 LAYERS",
120
- condition="有跨会话任务台账需求")
121
- check("B1 首次登记建卡成功", r.get("ok") is True and r.get("created") is True, r)
122
- g = T.get_task(cg, nid)
123
- _idx = cg.index["nodes"].get(nid) or {} # 层/权重以索引真源为准
124
- check("B2 读回六要素齐备(CCG 骨架)",
125
- g.get("goal") and g.get("plan") and g.get("acceptance")
126
- and g.get("boundary") and g.get("condition"), g)
127
- check("B3 落盘层=structural(使用者指定位置,不新增层)",
128
- _idx.get("layer") == "structural", _idx.get("layer"))
129
- check("B4 标签含 task 与 task:<slug>(可反向关联)",
130
- T.TASK_TAG in g.get("tags", []) and ("task:" + NAME) in g.get("tags", []),
131
- g.get("tags"))
132
- check("B5 重要性 0.8(进入写保护域,不可被随意覆写)",
133
- abs(float(_idx.get("importance") or 0) - T.DEFAULT_IMPORTANCE) < 1e-9,
134
- _idx.get("importance"))
135
- check("B6 状态缺省 active", g.get("status") == "active", g.get("status"))
136
-
137
- # ---------------- C. 幂等:同 slug 即同任务(症状④ 的机制解) ----------------
138
- print("\n[C] 幂等:同 slug 走同一节点更新,不新建卡")
139
- _before = len(_task_nodes(cg))
140
- r2 = T.upsert(cg, NAME, plan="1) 建 tasks.py 2) 接 MCP 3) 会话段 4) 测试(已更新)")
141
- check("C1 重复登记不新建卡(created=False)",
142
- r2.get("ok") is True and r2.get("created") is False, r2)
143
- check("C2 节点数不变(换表述不产生新任务)",
144
- len(_task_nodes(cg)) == _before, _task_nodes(cg))
145
- g2 = T.get_task(cg, nid)
146
- check("C3 未提供字段沿用旧值(goal 未被清空)",
147
- g2.get("goal") == "消除 AI 四症状失忆", g2.get("goal"))
148
- check("C4 已提供字段被覆盖(plan 更新生效)",
149
- "(已更新)" in (g2.get("plan") or ""), g2.get("plan"))
150
- check("C5 与 goals 不双写(任务走自有状态机,不依赖 goal_ 节点)",
151
- not [n for n in cg.index["nodes"] if n.startswith("goal_")],
152
- [n for n in cg.index["nodes"] if n.startswith("goal_")])
153
-
154
- # ---------------- D. 结果不可被静默清空 ----------------
155
- print("\n[D] 结果维护:不可静默清空")
156
- T.upsert(cg, NAME, result="首版结果:tasks.py 骨架落地")
157
- check("D1 结果可写入",
158
- "首版结果" in (T.get_task(cg, nid).get("result") or ""),
159
- T.get_task(cg, nid).get("result"))
160
- T.upsert(cg, NAME, note="仅改进度,不碰结果")
161
- check("D2 本次不带 result → 旧结果保留(非清空)",
162
- "首版结果" in (T.get_task(cg, nid).get("result") or ""),
163
- T.get_task(cg, nid).get("result"))
164
- T.upsert(cg, NAME, result="")
165
- check("D3 空串视为未提供 → 仍保留旧结果",
166
- "首版结果" in (T.get_task(cg, nid).get("result") or ""),
167
- T.get_task(cg, nid).get("result"))
168
-
169
- # ---------------- E. done 结果必填闸(症状③ 缺核验) ----------------
170
- print("\n[E] 完成闸:done 无结果拒收,缺一不收")
171
- e1 = T.upsert(cg, NAME4, status="done")
172
- check("E1 新任务直接 done 且无结果 → 拒收",
173
- bool(e1) and e1.get("ok") is False and "结果" in (e1.get("error") or ""), e1)
174
- check("E1b 拒收不留半成品节点(盘上无残留)",
175
- T.task_node_id(NAME4) not in cg.index["nodes"])
176
- T.upsert(cg, NAME2, goal="验证完成闸", plan="1) 造 active 卡 2) 裸转 done")
177
- n2 = T.task_node_id(NAME2)
178
- _c_before = (cg.get(n2) or {}).get("content") or ""
179
- e2 = T.set_status(cg, n2, "done")
180
- check("E2 已有任务裸转 done(无结果)→ 拒收",
181
- bool(e2) and e2.get("ok") is False, e2)
182
- _c_after = (cg.get(n2) or {}).get("content") or ""
183
- check("E2b 拒收后盘上内容逐字节不变(拒绝不是软提示)",
184
- hashlib.md5(_c_before.encode("utf-8")).hexdigest()
185
- == hashlib.md5(_c_after.encode("utf-8")).hexdigest())
186
- check("E2c 状态未被偷偷推进(仍 active)",
187
- T.get_task(cg, n2).get("status") == "active",
188
- T.get_task(cg, n2).get("status"))
189
- e3 = T.set_status(cg, n2, "done", result="已交付:完成闸 41 断言全绿")
190
- check("E3 带结果转 done → 通过",
191
- bool(e3) and e3.get("ok") is True, e3)
192
- check("E3b 状态落盘 done 且结果可检索",
193
- T.get_task(cg, n2).get("status") == "done"
194
- and "已交付" in (T.get_task(cg, n2).get("result") or ""),
195
- T.get_task(cg, n2).get("status"))
196
-
197
- # ---------------- F. 计划覆盖 + 计划变更累积(症状②) ----------------
198
- print("\n[F] 计划与变更:计划覆盖、变更累积")
199
- T.upsert(cg, NAME, plan="1) 建模块 2) 接 MCP 3) 会话段 4) 测试 5) 归档")
200
- check("F1 计划每轮覆盖更新(当前态唯一)",
201
- "5) 归档" in (T.get_task(cg, nid).get("plan") or ""),
202
- T.get_task(cg, nid).get("plan"))
203
- f2 = T.plan_add(cg, nid, "发现 add 是全量重建 fm,需先读旧 fm 再合并")
204
- check("F2 计划变更可追加(变更记入独立节)",
205
- bool(f2) and f2.get("ok") is True, f2)
206
- T.plan_add(cg, nid, "MCP 面 action 推导顺序调整:写意图优先于读意图")
207
- ch = T.get_task(cg, nid).get("changes") or ""
208
- check("F3 变更逐轮累积(两轮 = 两行,差异可追溯)",
209
- ch.count("- [") == 2, ch)
210
- check("F4 变更不覆盖计划(两节独立)",
211
- "5) 归档" in (T.get_task(cg, nid).get("plan") or ""), ch)
212
- _empty = T.plan_add(cg, nid, " ")
213
- check("F5 空变更拒收(不写空行噪声)",
214
- bool(_empty) and _empty.get("ok") is False, _empty)
215
-
216
- # ---------------- G. 状态机 ----------------
217
- print("\n[G] 状态机:四态可切换,未知态拒收")
218
- T.upsert(cg, NAME3, goal="MCP 面探针", plan="1) 推导 2) 冒烟")
219
- n3 = T.task_node_id(NAME3)
220
- check("G1 blocked 可切换",
221
- T.set_status(cg, n3, "blocked").get("ok") is True
222
- and T.get_task(cg, n3).get("status") == "blocked")
223
- T.set_status(cg, n3, "active")
224
- _bad = T.set_status(cg, n3, "moving")
225
- check("G2 未知状态拒收(状态机封闭)",
226
- bool(_bad) and _bad.get("ok") is False, _bad)
227
-
228
- # ---------------- H. 会话装配(症状① 的机制解) ----------------
229
- print("\n[H] 会话召回:带出进行中与近期完成,跨会话可见")
230
- st = T.session_tasks(cg)
231
- check("H1 进行中任务被带出(忘记已实现的解)",
232
- any(t["name"] == NAME for t in st["active"]), [t["name"] for t in st["active"]])
233
- check("H2 近期完成单列且带结果摘要",
234
- any(t["name"] == NAME2 and t.get("result") for t in st["done"]),
235
- st["done"])
236
- _other = MdCGSecure(_root, principal=Principal(
237
- actor="task_test_other", role="designer", can_write=True, can_admin=True,
238
- ops_allow=["*"], layers_allow=["*"], session="sess_other"))
239
- check("H3 换会话(新 Principal 同 root)仍带出任务(工程台账跨会话)",
240
- any(t["name"] == NAME
241
- for t in _other.session_recall()["tasks"]["active"]))
242
- check("H3b session_tasks 无 session 形参(设计:台账不按会话切分)",
243
- "session" not in inspect.signature(T.session_tasks).parameters,
244
- list(inspect.signature(T.session_tasks).parameters))
245
- pack = cg.session_recall()
246
- check("H4 session_recall 含 tasks 段(上下文装配面已接)",
247
- "tasks" in pack and any(t["name"] == NAME for t in pack["tasks"]["active"]),
248
- list(pack.get("tasks", {}).get("active", []))[:2])
249
- check("H5 预算裁剪上报字段在位(任务段最后让位)",
250
- "tasks_truncated" in pack, sorted(pack.keys()))
251
- check("H6 done 任务不进进行中段(不冒充未完成)",
252
- all(t["name"] != NAME2 for t in st["active"]),
253
- [t["name"] for t in st["active"]])
254
-
255
- # ---------------- I. 同族提示(只提示,不合并) ----------------
256
- print("\n[I] 同族提示:由人裁决,不自动合并")
257
- s_exact = T.find_similar(cg, NAME)
258
- check("I1 完全同名可判别(exists=True,防重复开工)",
259
- s_exact.get("exists") is True, s_exact)
260
- _cnt_before = len(_task_nodes(cg))
261
- s_near = T.find_similar(cg, NAME + "-续")
262
- check("I2 近名给出疑似同族(提示面可用)",
263
- isinstance(s_near.get("similar"), list), s_near)
264
- check("I3 提示不改盘(同族绝不自动合并)",
265
- len(_task_nodes(cg)) == _cnt_before, _task_nodes(cg))
266
- s_new = T.find_similar(cg, "完全无关的新任务-xyz")
267
- check("I4 全新名不误报同族(exists=False)",
268
- s_new.get("exists") is False, s_new)
269
-
270
- # ---------------- J. 边界:串号 / 检索 / 反向关联 ----------------
271
- print("\n[J] 边界:串号防护、检索面、知识反向关联")
272
- cg.add("trait_probe", "非任务的结构层节点(探针)", layer="structural",
273
- verification_basis="other", consistency=False, tags=["trait"])
274
- check("J1 非任务 structural 节点不混入清单(层内串号防护)",
275
- all(t["id"] != "trait_probe" for t in T.list_tasks(cg)["tasks"]),
276
- [t["id"] for t in T.list_tasks(cg)["tasks"]])
277
- _ids = _hits(cg, NAME, layer="structural")
278
- check("J2 任务节点在 structural 层可被检索(按需调用面)",
279
- nid in _ids, _ids)
280
- cg.add("kp_task_rel", "任务相关知识:四症状的机制解与验收判据",
281
- layer="knowledge", verification_basis="test", consistency=False,
282
- tags=["task:" + NAME])
283
- _kp = cg.get("kp_task_rel")
284
- check("J3 任务知识挂 knowledge 层并以 tags 反向关联",
285
- _kp.get("frontmatter", {}).get("layer") == "knowledge"
286
- and ("task:" + NAME) in (_kp.get("frontmatter", {}).get("tags") or []),
287
- _kp.get("frontmatter", {}).get("tags"))
288
- check("J4 任务清单按 layer 过滤(知识节点不入台账)",
289
- all(t["id"] != "kp_task_rel" for t in T.list_tasks(cg)["tasks"]))
290
-
291
- # ---------------- K. 留痕:复用既有审计面 ----------------
292
- print("\n[K] 生命周期留痕:复用 _audit,不新造日志格式")
293
- _seen = []
294
- _orig = cg._audit
295
-
296
- def _spy(op, nid_, **kw):
297
- _seen.append(op)
298
- return _orig(op, nid_, **kw)
299
-
300
- cg._audit = _spy
301
- try:
302
- T.upsert(cg, "审计探针-任务", plan="x")
303
- T.plan_add(cg, T.task_node_id("审计探针-任务"), "变更一行")
304
- finally:
305
- cg._audit = _orig
306
- check("K1 建卡留痕 task_open", "task_open" in _seen, _seen)
307
- check("K2 更新留痕 task_update", "task_update" in _seen, _seen)
308
-
309
- # ---------------- L. MCP 面对位 ----------------
310
- print("\n[L] MCP 面:action 推导不吞写意图 / schema 可传 / 缺省 list")
311
- SIG = M._action_sig
312
- check("L1 task+name → open", SIG({"name": "X"}, "task") == ("open", "name"),
313
- SIG({"name": "X"}, "task"))
314
- check("L2 task+change → plan_add",
315
- SIG({"change": "c"}, "task") == ("plan_add", "change"),
316
- SIG({"change": "c"}, "task"))
317
- check("L3 task+name+change → open(open 兼容 change,写意图不丢)",
318
- SIG({"name": "X", "change": "c"}, "task") == ("open", "name"),
319
- SIG({"name": "X", "change": "c"}, "task"))
320
- check("L4 task+node_id → get",
321
- SIG({"node_id": "task_x"}, "task") == ("get", "node_id"),
322
- SIG({"node_id": "task_x"}, "task"))
323
- check("L5 task+node_id+change → plan_add(写优先于读,不静默当只读)",
324
- SIG({"node_id": "task_x", "change": "c"}, "task") == ("plan_add", "change"),
325
- SIG({"node_id": "task_x", "change": "c"}, "task"))
326
- check("L6 task+task_status → status",
327
- SIG({"task_status": "done"}, "task") == ("status", "task_status"),
328
- SIG({"task_status": "done"}, "task"))
329
- check("L7 task 无签名不猜(交 _ACTION_DEFAULT 承接)",
330
- SIG({}, "task") == (None, None), SIG({}, "task"))
331
- check("L8 _ACTION_DEFAULT['task'] == 'list'",
332
- M._ACTION_DEFAULT.get("task") == "list", M._ACTION_DEFAULT.get("task"))
333
- _src = open(os.path.join(_HERE, "mcp_server.py"), encoding="utf-8").read()
334
- _vals = set(re.findall(r'a\.get\("action"\)\s*or\s*"([a-z_]+)"', _src))
335
- check("L9 缺省字面量在源码真实存在(防幻影表)", "list" in _vals, sorted(_vals))
336
-
337
- out = M._cg_call(cg, {"op": "task", "name": NAME3, "plan": "1) 推导 2) 冒烟"})
338
- check("L10 op=task 缺 action → 推导 open 且透出(不静默)",
339
- out.get("ok") is True and out.get("action_derived") is True
340
- and out.get("action") == "open", out)
341
-
342
- def _chg():
343
- _g = M._cg_call(cg, {"op": "task", "action": "get", "node_id": n3})
344
- return _g.get("changes") or ""
345
-
346
- _c_before = _chg()
347
- out2 = M._cg_call(cg, {"op": "task", "node_id": n3, "change": "MCP 面追加一行"})
348
- check("L11 node_id+change 真实落盘(写意图未被吞)",
349
- out2.get("ok") is True and _chg().count("- [") == _c_before.count("- [") + 1,
350
- out2)
351
-
352
- out3 = M._cg_call(cg, {"op": "task"})
353
- check("L12 无签名 → 缺省 list 且透出 action_derived",
354
- out3.get("action_derived") is True and out3.get("action") == "list"
355
- and bool(out3.get("tasks")) is True, out3)
356
- out4 = M._cg_call(cg, {"op": "task", "action": "nope", "name": NAME})
357
- check("L13 未知 action fail-closed(返回 error,不静默降级)",
358
- out4.get("ok") is False and bool(out4.get("error")), out4)
359
- out5 = M._cg_call(cg, {"op": "task", "action": "session"})
360
- check("L14 action=session 会话装配面可经 MCP 取用",
361
- out5.get("ok") is True and bool(out5.get("active")), out5)
362
- out6 = M._cg_call(cg, {"op": "task", "action": "find", "name": NAME})
363
- check("L15 action=find 同族提示可经 MCP 取用",
364
- out6.get("ok") is True, out6)
365
-
366
- _tool = [t for t in M.KERNEL_TOOLS if t.get("name") == "cg"][0]
367
- _props = _tool["inputSchema"]["properties"]
368
- check("L16 op 枚举含 task(客户端可见面同步)",
369
- "task" in [x.strip() for x in _props["op"]["description"].split("|")])
370
- _miss = [k for k in ("plan", "result", "task_status", "acceptance", "boundary",
371
- "active_limit", "done_limit") if k not in _props]
372
- check("L17 cg schema 已声明 task 参数(客户端传得进来)", not _miss, _miss)
373
- check("L18 tokens.ALL_OPS 含 task(跨面真源同步)",
374
- "task" in TK.ALL_OPS, [o for o in TK.ALL_OPS if o == "task"])
375
-
376
- # ---------------- M. 权限闸 ----------------
377
- print("\n[M] 权限闸:写权限不够则拒,角色白名单同步")
378
- _guest = MdCGSecure(os.path.join(tmp, "guest_root"),
379
- principal=Principal(actor="guest1", role="guest",
380
- can_write=False, can_admin=False))
381
- _ge = _raises(lambda: T.upsert(_guest, NAME5, plan="x"))
382
- check("M1 无写权限角色写任务被拒(权限闸不可绕)",
383
- isinstance(_ge, AccessDenied), _ge)
384
- _rec = TK.ROLE_SPECS["record"]
385
- check("M2 record 角色 ops 白名单含 task 且可写 structural 层",
386
- "task" in _rec["ops_allow"] and "structural" in _rec["layers_allow"],
387
- (_rec["ops_allow"], _rec["layers_allow"]))
388
- _owner = Principal(actor="owner", role="designer", can_write=True,
389
- can_admin=True, ops_allow=["*"], layers_allow=["*"])
390
- _narrow = TK.narrowed_principal(_owner, "record")
391
- check("M3 收窄身份(记录单元)可执行 task(本职:保存过程与结果)",
392
- _narrow.allows_op("task") is True, _narrow.ops_allow)
393
- _rcg = MdCGSecure(os.path.join(tmp, "record_root"), principal=_narrow)
394
- _ro = T.upsert(_rcg, "记录单元-任务探针", plan="x")
395
- check("M4 收窄身份真实落盘成功(端到端)", _ro.get("ok") is True, _ro)
396
- finally:
397
- shutil.rmtree(tmp, ignore_errors=True)
398
-
399
- print("\n%s %d 项断言,%d 失败" % ("ALL GREEN" if not _fails else "FAILED",
400
- _n[0], len(_fails)))
401
- if _fails:
402
- for f in _fails:
403
- print(" - %s" % f)
404
- return 1
405
- return 0
406
-
407
-
408
- if __name__ == "__main__":
409
- sys.exit(main())
1
+ # -*- coding: utf-8 -*-
2
+ """结构层任务实体(md_cg/tasks.py)验收矩阵(2026-09-16)。
3
+
4
+ 蓝图=消除 AI 失忆四症状,断言按症状逐条对位:
5
+
6
+ ① 忘记已实现的工程 → H 组:session_tasks / session_recall 任务段,
7
+ 且**不按 session 过滤**(工程台账跨会话可见,这正是失忆的解)
8
+ ② 计划与实际不符 → F 组:计划每轮覆盖更新 + 「计划变更」节逐轮累积
9
+ ③ 缺核验 → E 组:done 时结果必填闸(缺一不收),拒收后**盘上内容逐字节不变**
10
+ ④ 换表述即新任务 → A/C/I 组:身份=语义 slug(非内容哈希);同 slug 幂等更新
11
+ 不新增节点;同族只提示、不自动合并
12
+
13
+ 另含 MCP 面对位(L 组:action 推导不吞写意图 / schema 参数声明 / 缺省 list 冒烟 /
14
+ 未知 action fail-closed)与边界(J 组:串号防护、检索面、反向关联;M 组:权限闸)。
15
+ 脚本式 assert + 退出码,风格与 test_branches.py / test_action_derive.py 一致。
16
+ """
17
+
18
+ import os
19
+ import re
20
+ import sys
21
+ import shutil
22
+ import inspect
23
+ import tempfile
24
+ import hashlib
25
+
26
+ _HERE = os.path.dirname(os.path.abspath(__file__))
27
+ _REPO = os.path.dirname(_HERE)
28
+ if _REPO not in sys.path:
29
+ sys.path.insert(0, _REPO)
30
+
31
+ try:
32
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
33
+ except Exception:
34
+ pass
35
+
36
+ from md_cg import mcp_server as M
37
+ from md_cg import tasks as T
38
+ from md_cg import tokens as TK
39
+ from md_cg.mdcos import MdCGSecure
40
+ from md_cg.security import Principal, AccessDenied
41
+
42
+ # 语料命名(互不串扰,各症状用独立任务名)
43
+ NAME = "记忆失忆修复-工程"
44
+ NAME2 = "任务实体-done闸探针"
45
+ NAME3 = "mcp面-任务探针"
46
+ NAME4 = "任务-未开先done"
47
+ NAME5 = "越权任务"
48
+
49
+ _fails = []
50
+ _n = [0]
51
+
52
+
53
+ def check(name, cond, detail=None):
54
+ _n[0] += 1
55
+ if cond:
56
+ print(" ok %s" % name)
57
+ else:
58
+ print("FAIL %s %r" % (name, detail))
59
+ _fails.append(name)
60
+
61
+
62
+ def _raises(fn):
63
+ try:
64
+ fn()
65
+ except Exception as e: # noqa: BLE001 —— 测试需拿到任何异常作证据
66
+ return e
67
+ return None
68
+
69
+
70
+ def _mk_cg(root, **kw):
71
+ p = Principal(actor="task_test", role="designer", can_write=True, can_admin=True,
72
+ ops_allow=["*"], layers_allow=["*"], **kw)
73
+ return MdCGSecure(root, principal=p)
74
+
75
+
76
+ def _task_nodes(cg):
77
+ return sorted(n for n in cg.index["nodes"] if n.startswith(T.TASK_PREFIX))
78
+
79
+
80
+ def _hits(cg, q, **kw):
81
+ res, _meta = cg.search(q, **kw)
82
+ return [h[0].get("id") for h in res]
83
+
84
+
85
+ def main():
86
+ tmp = tempfile.mkdtemp(prefix="mdcg_tasks_")
87
+ try:
88
+ _root = os.path.join(tmp, "root")
89
+ cg = _mk_cg(_root)
90
+ nid = T.task_node_id(NAME)
91
+
92
+ # ---------------- A. 身份判据=语义 slug(症状④ 的根) ----------------
93
+ print("\n[A] 身份判据:语义 slug,非内容哈希")
94
+ check("A1 中文名原样保留(语义身份可读)",
95
+ T.slugify(NAME) == NAME, T.slugify(NAME))
96
+ check("A2 路径分隔符折叠(防目录穿越)",
97
+ T.slugify("a/b\\c") == "a-b-c", T.slugify("a/b\\c"))
98
+ _trav = T.slugify("../../etc/passwd")
99
+ check("A3 `..` 与 `/` 全部折叠,不留穿越形态",
100
+ ".." not in _trav and "/" not in _trav and "\\" not in _trav, _trav)
101
+ check("A4 空白/纯符号名拒收(无身份不建卡)",
102
+ T.task_node_id(" ") is None or T.slugify(" ") == "", T.slugify(" "))
103
+ check("A4b 纯符号名 slug 为空", T.slugify("!!!") == "", T.slugify("!!!"))
104
+ check("A5 已带前缀不重复叠(task_x → task_x)",
105
+ T.task_node_id("task_x") == "task_x" == T.task_node_id("x"),
106
+ (T.task_node_id("task_x"), T.task_node_id("x")))
107
+ check("A6 超长名截断(≥64 上限护栏)",
108
+ len(T.task_node_id("a" * 200)) <= len(T.TASK_PREFIX) + 64,
109
+ len(T.task_node_id("a" * 200)))
110
+ _o = T.upsert(cg, "任务 名(一)", plan="探针")
111
+ check("A7 归一化透明(原名与 slug 同返,不静默改名)",
112
+ _o.get("ok") and _o.get("slug_normalized") == "任务-名-一"
113
+ and _o.get("node_id") == "task_任务-名-一", _o)
114
+
115
+ # ---------------- B. 创建与读回(结构层定位) ----------------
116
+ print("\n[B] 创建与读回:structural 层一等节点")
117
+ r = T.upsert(cg, NAME, goal="消除 AI 四症状失忆",
118
+ plan="1) 建 tasks.py 2) 接 MCP 3) 会话段 4) 测试",
119
+ acceptance="四症状逐条有对位断言", boundary="不动 LAYERS",
120
+ condition="有跨会话任务台账需求")
121
+ check("B1 首次登记建卡成功", r.get("ok") is True and r.get("created") is True, r)
122
+ g = T.get_task(cg, nid)
123
+ _idx = cg.index["nodes"].get(nid) or {} # 层/权重以索引真源为准
124
+ check("B2 读回六要素齐备(CCG 骨架)",
125
+ g.get("goal") and g.get("plan") and g.get("acceptance")
126
+ and g.get("boundary") and g.get("condition"), g)
127
+ check("B3 落盘层=structural(使用者指定位置,不新增层)",
128
+ _idx.get("layer") == "structural", _idx.get("layer"))
129
+ check("B4 标签含 task 与 task:<slug>(可反向关联)",
130
+ T.TASK_TAG in g.get("tags", []) and ("task:" + NAME) in g.get("tags", []),
131
+ g.get("tags"))
132
+ check("B5 重要性 0.8(进入写保护域,不可被随意覆写)",
133
+ abs(float(_idx.get("importance") or 0) - T.DEFAULT_IMPORTANCE) < 1e-9,
134
+ _idx.get("importance"))
135
+ check("B6 状态缺省 active", g.get("status") == "active", g.get("status"))
136
+
137
+ # ---------------- C. 幂等:同 slug 即同任务(症状④ 的机制解) ----------------
138
+ print("\n[C] 幂等:同 slug 走同一节点更新,不新建卡")
139
+ _before = len(_task_nodes(cg))
140
+ r2 = T.upsert(cg, NAME, plan="1) 建 tasks.py 2) 接 MCP 3) 会话段 4) 测试(已更新)")
141
+ check("C1 重复登记不新建卡(created=False)",
142
+ r2.get("ok") is True and r2.get("created") is False, r2)
143
+ check("C2 节点数不变(换表述不产生新任务)",
144
+ len(_task_nodes(cg)) == _before, _task_nodes(cg))
145
+ g2 = T.get_task(cg, nid)
146
+ check("C3 未提供字段沿用旧值(goal 未被清空)",
147
+ g2.get("goal") == "消除 AI 四症状失忆", g2.get("goal"))
148
+ check("C4 已提供字段被覆盖(plan 更新生效)",
149
+ "(已更新)" in (g2.get("plan") or ""), g2.get("plan"))
150
+ check("C5 与 goals 不双写(任务走自有状态机,不依赖 goal_ 节点)",
151
+ not [n for n in cg.index["nodes"] if n.startswith("goal_")],
152
+ [n for n in cg.index["nodes"] if n.startswith("goal_")])
153
+
154
+ # ---------------- D. 结果不可被静默清空 ----------------
155
+ print("\n[D] 结果维护:不可静默清空")
156
+ T.upsert(cg, NAME, result="首版结果:tasks.py 骨架落地")
157
+ check("D1 结果可写入",
158
+ "首版结果" in (T.get_task(cg, nid).get("result") or ""),
159
+ T.get_task(cg, nid).get("result"))
160
+ T.upsert(cg, NAME, note="仅改进度,不碰结果")
161
+ check("D2 本次不带 result → 旧结果保留(非清空)",
162
+ "首版结果" in (T.get_task(cg, nid).get("result") or ""),
163
+ T.get_task(cg, nid).get("result"))
164
+ T.upsert(cg, NAME, result="")
165
+ check("D3 空串视为未提供 → 仍保留旧结果",
166
+ "首版结果" in (T.get_task(cg, nid).get("result") or ""),
167
+ T.get_task(cg, nid).get("result"))
168
+
169
+ # ---------------- E. done 结果必填闸(症状③ 缺核验) ----------------
170
+ print("\n[E] 完成闸:done 无结果拒收,缺一不收")
171
+ e1 = T.upsert(cg, NAME4, status="done")
172
+ check("E1 新任务直接 done 且无结果 → 拒收",
173
+ bool(e1) and e1.get("ok") is False and "结果" in (e1.get("error") or ""), e1)
174
+ check("E1b 拒收不留半成品节点(盘上无残留)",
175
+ T.task_node_id(NAME4) not in cg.index["nodes"])
176
+ T.upsert(cg, NAME2, goal="验证完成闸", plan="1) 造 active 卡 2) 裸转 done")
177
+ n2 = T.task_node_id(NAME2)
178
+ _c_before = (cg.get(n2) or {}).get("content") or ""
179
+ e2 = T.set_status(cg, n2, "done")
180
+ check("E2 已有任务裸转 done(无结果)→ 拒收",
181
+ bool(e2) and e2.get("ok") is False, e2)
182
+ _c_after = (cg.get(n2) or {}).get("content") or ""
183
+ check("E2b 拒收后盘上内容逐字节不变(拒绝不是软提示)",
184
+ hashlib.md5(_c_before.encode("utf-8")).hexdigest()
185
+ == hashlib.md5(_c_after.encode("utf-8")).hexdigest())
186
+ check("E2c 状态未被偷偷推进(仍 active)",
187
+ T.get_task(cg, n2).get("status") == "active",
188
+ T.get_task(cg, n2).get("status"))
189
+ e3 = T.set_status(cg, n2, "done", result="已交付:完成闸 41 断言全绿")
190
+ check("E3 带结果转 done → 通过",
191
+ bool(e3) and e3.get("ok") is True, e3)
192
+ check("E3b 状态落盘 done 且结果可检索",
193
+ T.get_task(cg, n2).get("status") == "done"
194
+ and "已交付" in (T.get_task(cg, n2).get("result") or ""),
195
+ T.get_task(cg, n2).get("status"))
196
+
197
+ # ---------------- F. 计划覆盖 + 计划变更累积(症状②) ----------------
198
+ print("\n[F] 计划与变更:计划覆盖、变更累积")
199
+ T.upsert(cg, NAME, plan="1) 建模块 2) 接 MCP 3) 会话段 4) 测试 5) 归档")
200
+ check("F1 计划每轮覆盖更新(当前态唯一)",
201
+ "5) 归档" in (T.get_task(cg, nid).get("plan") or ""),
202
+ T.get_task(cg, nid).get("plan"))
203
+ f2 = T.plan_add(cg, nid, "发现 add 是全量重建 fm,需先读旧 fm 再合并")
204
+ check("F2 计划变更可追加(变更记入独立节)",
205
+ bool(f2) and f2.get("ok") is True, f2)
206
+ T.plan_add(cg, nid, "MCP 面 action 推导顺序调整:写意图优先于读意图")
207
+ ch = T.get_task(cg, nid).get("changes") or ""
208
+ check("F3 变更逐轮累积(两轮 = 两行,差异可追溯)",
209
+ ch.count("- [") == 2, ch)
210
+ check("F4 变更不覆盖计划(两节独立)",
211
+ "5) 归档" in (T.get_task(cg, nid).get("plan") or ""), ch)
212
+ _empty = T.plan_add(cg, nid, " ")
213
+ check("F5 空变更拒收(不写空行噪声)",
214
+ bool(_empty) and _empty.get("ok") is False, _empty)
215
+
216
+ # ---------------- G. 状态机 ----------------
217
+ print("\n[G] 状态机:四态可切换,未知态拒收")
218
+ T.upsert(cg, NAME3, goal="MCP 面探针", plan="1) 推导 2) 冒烟")
219
+ n3 = T.task_node_id(NAME3)
220
+ check("G1 blocked 可切换",
221
+ T.set_status(cg, n3, "blocked").get("ok") is True
222
+ and T.get_task(cg, n3).get("status") == "blocked")
223
+ T.set_status(cg, n3, "active")
224
+ _bad = T.set_status(cg, n3, "moving")
225
+ check("G2 未知状态拒收(状态机封闭)",
226
+ bool(_bad) and _bad.get("ok") is False, _bad)
227
+
228
+ # ---------------- H. 会话装配(症状① 的机制解) ----------------
229
+ print("\n[H] 会话召回:带出进行中与近期完成,跨会话可见")
230
+ st = T.session_tasks(cg)
231
+ check("H1 进行中任务被带出(忘记已实现的解)",
232
+ any(t["name"] == NAME for t in st["active"]), [t["name"] for t in st["active"]])
233
+ check("H2 近期完成单列且带结果摘要",
234
+ any(t["name"] == NAME2 and t.get("result") for t in st["done"]),
235
+ st["done"])
236
+ _other = MdCGSecure(_root, principal=Principal(
237
+ actor="task_test_other", role="designer", can_write=True, can_admin=True,
238
+ ops_allow=["*"], layers_allow=["*"], session="sess_other"))
239
+ check("H3 换会话(新 Principal 同 root)仍带出任务(工程台账跨会话)",
240
+ any(t["name"] == NAME
241
+ for t in _other.session_recall()["tasks"]["active"]))
242
+ check("H3b session_tasks 无 session 形参(设计:台账不按会话切分)",
243
+ "session" not in inspect.signature(T.session_tasks).parameters,
244
+ list(inspect.signature(T.session_tasks).parameters))
245
+ pack = cg.session_recall()
246
+ check("H4 session_recall 含 tasks 段(上下文装配面已接)",
247
+ "tasks" in pack and any(t["name"] == NAME for t in pack["tasks"]["active"]),
248
+ list(pack.get("tasks", {}).get("active", []))[:2])
249
+ check("H5 预算裁剪上报字段在位(任务段最后让位)",
250
+ "tasks_truncated" in pack, sorted(pack.keys()))
251
+ check("H6 done 任务不进进行中段(不冒充未完成)",
252
+ all(t["name"] != NAME2 for t in st["active"]),
253
+ [t["name"] for t in st["active"]])
254
+
255
+ # ---------------- I. 同族提示(只提示,不合并) ----------------
256
+ print("\n[I] 同族提示:由人裁决,不自动合并")
257
+ s_exact = T.find_similar(cg, NAME)
258
+ check("I1 完全同名可判别(exists=True,防重复开工)",
259
+ s_exact.get("exists") is True, s_exact)
260
+ _cnt_before = len(_task_nodes(cg))
261
+ s_near = T.find_similar(cg, NAME + "-续")
262
+ check("I2 近名给出疑似同族(提示面可用)",
263
+ isinstance(s_near.get("similar"), list), s_near)
264
+ check("I3 提示不改盘(同族绝不自动合并)",
265
+ len(_task_nodes(cg)) == _cnt_before, _task_nodes(cg))
266
+ s_new = T.find_similar(cg, "完全无关的新任务-xyz")
267
+ check("I4 全新名不误报同族(exists=False)",
268
+ s_new.get("exists") is False, s_new)
269
+
270
+ # ---------------- J. 边界:串号 / 检索 / 反向关联 ----------------
271
+ print("\n[J] 边界:串号防护、检索面、知识反向关联")
272
+ cg.add("trait_probe", "非任务的结构层节点(探针)", layer="structural",
273
+ verification_basis="other", consistency=False, tags=["trait"])
274
+ check("J1 非任务 structural 节点不混入清单(层内串号防护)",
275
+ all(t["id"] != "trait_probe" for t in T.list_tasks(cg)["tasks"]),
276
+ [t["id"] for t in T.list_tasks(cg)["tasks"]])
277
+ _ids = _hits(cg, NAME, layer="structural")
278
+ check("J2 任务节点在 structural 层可被检索(按需调用面)",
279
+ nid in _ids, _ids)
280
+ cg.add("kp_task_rel", "任务相关知识:四症状的机制解与验收判据",
281
+ layer="knowledge", verification_basis="test", consistency=False,
282
+ tags=["task:" + NAME])
283
+ _kp = cg.get("kp_task_rel")
284
+ check("J3 任务知识挂 knowledge 层并以 tags 反向关联",
285
+ _kp.get("frontmatter", {}).get("layer") == "knowledge"
286
+ and ("task:" + NAME) in (_kp.get("frontmatter", {}).get("tags") or []),
287
+ _kp.get("frontmatter", {}).get("tags"))
288
+ check("J4 任务清单按 layer 过滤(知识节点不入台账)",
289
+ all(t["id"] != "kp_task_rel" for t in T.list_tasks(cg)["tasks"]))
290
+
291
+ # ---------------- K. 留痕:复用既有审计面 ----------------
292
+ print("\n[K] 生命周期留痕:复用 _audit,不新造日志格式")
293
+ _seen = []
294
+ _orig = cg._audit
295
+
296
+ def _spy(op, nid_, **kw):
297
+ _seen.append(op)
298
+ return _orig(op, nid_, **kw)
299
+
300
+ cg._audit = _spy
301
+ try:
302
+ T.upsert(cg, "审计探针-任务", plan="x")
303
+ T.plan_add(cg, T.task_node_id("审计探针-任务"), "变更一行")
304
+ finally:
305
+ cg._audit = _orig
306
+ check("K1 建卡留痕 task_open", "task_open" in _seen, _seen)
307
+ check("K2 更新留痕 task_update", "task_update" in _seen, _seen)
308
+
309
+ # ---------------- L. MCP 面对位 ----------------
310
+ print("\n[L] MCP 面:action 推导不吞写意图 / schema 可传 / 缺省 list")
311
+ SIG = M._action_sig
312
+ check("L1 task+name → open", SIG({"name": "X"}, "task") == ("open", "name"),
313
+ SIG({"name": "X"}, "task"))
314
+ check("L2 task+change → plan_add",
315
+ SIG({"change": "c"}, "task") == ("plan_add", "change"),
316
+ SIG({"change": "c"}, "task"))
317
+ check("L3 task+name+change → open(open 兼容 change,写意图不丢)",
318
+ SIG({"name": "X", "change": "c"}, "task") == ("open", "name"),
319
+ SIG({"name": "X", "change": "c"}, "task"))
320
+ check("L4 task+node_id → get",
321
+ SIG({"node_id": "task_x"}, "task") == ("get", "node_id"),
322
+ SIG({"node_id": "task_x"}, "task"))
323
+ check("L5 task+node_id+change → plan_add(写优先于读,不静默当只读)",
324
+ SIG({"node_id": "task_x", "change": "c"}, "task") == ("plan_add", "change"),
325
+ SIG({"node_id": "task_x", "change": "c"}, "task"))
326
+ check("L6 task+task_status → status",
327
+ SIG({"task_status": "done"}, "task") == ("status", "task_status"),
328
+ SIG({"task_status": "done"}, "task"))
329
+ check("L7 task 无签名不猜(交 _ACTION_DEFAULT 承接)",
330
+ SIG({}, "task") == (None, None), SIG({}, "task"))
331
+ check("L8 _ACTION_DEFAULT['task'] == 'list'",
332
+ M._ACTION_DEFAULT.get("task") == "list", M._ACTION_DEFAULT.get("task"))
333
+ _src = open(os.path.join(_HERE, "mcp_server.py"), encoding="utf-8").read()
334
+ _vals = set(re.findall(r'a\.get\("action"\)\s*or\s*"([a-z_]+)"', _src))
335
+ check("L9 缺省字面量在源码真实存在(防幻影表)", "list" in _vals, sorted(_vals))
336
+
337
+ out = M._cg_call(cg, {"op": "task", "name": NAME3, "plan": "1) 推导 2) 冒烟"})
338
+ check("L10 op=task 缺 action → 推导 open 且透出(不静默)",
339
+ out.get("ok") is True and out.get("action_derived") is True
340
+ and out.get("action") == "open", out)
341
+
342
+ def _chg():
343
+ _g = M._cg_call(cg, {"op": "task", "action": "get", "node_id": n3})
344
+ return _g.get("changes") or ""
345
+
346
+ _c_before = _chg()
347
+ out2 = M._cg_call(cg, {"op": "task", "node_id": n3, "change": "MCP 面追加一行"})
348
+ check("L11 node_id+change 真实落盘(写意图未被吞)",
349
+ out2.get("ok") is True and _chg().count("- [") == _c_before.count("- [") + 1,
350
+ out2)
351
+
352
+ out3 = M._cg_call(cg, {"op": "task"})
353
+ check("L12 无签名 → 缺省 list 且透出 action_derived",
354
+ out3.get("action_derived") is True and out3.get("action") == "list"
355
+ and bool(out3.get("tasks")) is True, out3)
356
+ out4 = M._cg_call(cg, {"op": "task", "action": "nope", "name": NAME})
357
+ check("L13 未知 action fail-closed(返回 error,不静默降级)",
358
+ out4.get("ok") is False and bool(out4.get("error")), out4)
359
+ out5 = M._cg_call(cg, {"op": "task", "action": "session"})
360
+ check("L14 action=session 会话装配面可经 MCP 取用",
361
+ out5.get("ok") is True and bool(out5.get("active")), out5)
362
+ out6 = M._cg_call(cg, {"op": "task", "action": "find", "name": NAME})
363
+ check("L15 action=find 同族提示可经 MCP 取用",
364
+ out6.get("ok") is True, out6)
365
+
366
+ _tool = [t for t in M.KERNEL_TOOLS if t.get("name") == "cg"][0]
367
+ _props = _tool["inputSchema"]["properties"]
368
+ check("L16 op 枚举含 task(客户端可见面同步)",
369
+ "task" in [x.strip() for x in _props["op"]["description"].split("|")])
370
+ _miss = [k for k in ("plan", "result", "task_status", "acceptance", "boundary",
371
+ "active_limit", "done_limit") if k not in _props]
372
+ check("L17 cg schema 已声明 task 参数(客户端传得进来)", not _miss, _miss)
373
+ check("L18 tokens.ALL_OPS 含 task(跨面真源同步)",
374
+ "task" in TK.ALL_OPS, [o for o in TK.ALL_OPS if o == "task"])
375
+
376
+ # ---------------- M. 权限闸 ----------------
377
+ print("\n[M] 权限闸:写权限不够则拒,角色白名单同步")
378
+ _guest = MdCGSecure(os.path.join(tmp, "guest_root"),
379
+ principal=Principal(actor="guest1", role="guest",
380
+ can_write=False, can_admin=False))
381
+ _ge = _raises(lambda: T.upsert(_guest, NAME5, plan="x"))
382
+ check("M1 无写权限角色写任务被拒(权限闸不可绕)",
383
+ isinstance(_ge, AccessDenied), _ge)
384
+ _rec = TK.ROLE_SPECS["record"]
385
+ check("M2 record 角色 ops 白名单含 task 且可写 structural 层",
386
+ "task" in _rec["ops_allow"] and "structural" in _rec["layers_allow"],
387
+ (_rec["ops_allow"], _rec["layers_allow"]))
388
+ _owner = Principal(actor="owner", role="designer", can_write=True,
389
+ can_admin=True, ops_allow=["*"], layers_allow=["*"])
390
+ _narrow = TK.narrowed_principal(_owner, "record")
391
+ check("M3 收窄身份(记录单元)可执行 task(本职:保存过程与结果)",
392
+ _narrow.allows_op("task") is True, _narrow.ops_allow)
393
+ _rcg = MdCGSecure(os.path.join(tmp, "record_root"), principal=_narrow)
394
+ _ro = T.upsert(_rcg, "记录单元-任务探针", plan="x")
395
+ check("M4 收窄身份真实落盘成功(端到端)", _ro.get("ok") is True, _ro)
396
+ finally:
397
+ shutil.rmtree(tmp, ignore_errors=True)
398
+
399
+ print("\n%s %d 项断言,%d 失败" % ("ALL GREEN" if not _fails else "FAILED",
400
+ _n[0], len(_fails)))
401
+ if _fails:
402
+ for f in _fails:
403
+ print(" - %s" % f)
404
+ return 1
405
+ return 0
406
+
407
+
408
+ if __name__ == "__main__":
409
+ sys.exit(main())