@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.
- package/README.md +552 -465
- package/codebuddy/CODEBUDDY.md +11 -3
- package/codebuddy/README.md +92 -90
- package/codebuddy/mcp.json +27 -27
- 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
- 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
- package/docs/README.md +143 -111
- package/docs/discipline/harnesses.yaml +244 -226
- package/docs/discipline/templates/full.md.tmpl +61 -61
- package/docs/discipline/templates/rules.mdc.tmpl +68 -0
- package/docs/discipline/templates/skill.md.tmpl +23 -23
- 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
- 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
- package/docs/eval/bench_lingshu_self/bench_self.py +140 -0
- package/docs/eval/bench_lingshu_self/self_bench_result.json +404 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/docs/images/lingshu-moonlight-covenant-poster-preview.jpg +0 -0
- package/docs/images/lingshu-moonlight-covenant-poster.png +0 -0
- 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
- package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +646 -646
- package/docs/mdcg/lingshu_tutorial.html +14449 -14449
- package/docs/mdcg/release_v0.4.11.md +49 -0
- package/docs/mdcg/release_v0.4.5.md +55 -55
- package/docs/mdcg/tool_table_v0.3.0.md +117 -117
- 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
- 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
- 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
- package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +54 -0
- 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
- 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
- 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
- package/docs/mdcg//347/274/272/345/217/243/345/215/225_P0/346/224/266/345/217/243_v0.1.md +270 -270
- 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
- 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
- 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
- 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
- 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
- package/docs/swarm//350/234/202/347/276/244/344/272/222/350/201/224_v0.1.md +704 -704
- 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
- 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
- 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
- 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
- package/docs/theory//346/231/272/350/203/275/350/256/2723.4.md +5260 -5260
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/dsh/README.md +82 -82
- package/dsh/cordis.yml.example +139 -139
- package/dsh/update-lingshu.bat +11 -11
- package/lib/bridge.d.ts +9 -0
- package/lib/bridge.js +35 -0
- package/lib/hooks.js +36 -2
- package/lib/index.js +7 -1
- package/lib/lib/roleplay_web.js +116 -29
- package/lib/lib/token_store.d.ts +7 -1
- package/lib/lib/token_store.js +12 -3
- package/md_cg/__init__.py +7 -7
- package/md_cg/audit.py +379 -368
- package/md_cg/autonomy.py +287 -287
- package/md_cg/backfill.py +1328 -1327
- package/md_cg/backfill_bigdomain.py +34 -34
- package/md_cg/backfill_bucket_zh.py +35 -0
- package/md_cg/bench6_arms.py +410 -410
- package/md_cg/bench6_common.py +230 -230
- package/md_cg/bench6_competitors.py +212 -212
- package/md_cg/bench_axis_domain.py +257 -257
- package/md_cg/bench_blind_comp.py +308 -308
- package/md_cg/bench_e2e_judge.py +532 -0
- package/md_cg/bench_e2e_locomo_qa.py +368 -0
- package/md_cg/bench_e2e_qa.py +256 -0
- package/md_cg/bench_en_atoms_public.py +230 -230
- package/md_cg/bench_governance.py +348 -348
- package/md_cg/bench_lme_zh.py +410 -410
- package/md_cg/bench_locomo.py +121 -121
- package/md_cg/bench_locomo_zh.py +450 -450
- package/md_cg/bench_locomo_zh_public.py +147 -147
- package/md_cg/bench_longmem.py +112 -112
- package/md_cg/bench_membench.py +632 -632
- package/md_cg/bench_p0.py +149 -149
- package/md_cg/bench_progressive.py +287 -287
- package/md_cg/bench_role_views.py +238 -238
- package/md_cg/bench_task_ab.py +243 -243
- package/md_cg/bench_task_ab_llm.py +408 -408
- package/md_cg/bench_unified_en.py +204 -204
- package/md_cg/bench_zh_mad.py +601 -601
- package/md_cg/blindspot_tickets.py +123 -123
- package/md_cg/branches.py +301 -285
- package/md_cg/build_postings.py +73 -73
- package/md_cg/ccgc.py +1006 -948
- package/md_cg/census.py +132 -132
- package/md_cg/chain.py +315 -300
- package/md_cg/codeindex.py +531 -531
- package/md_cg/coldverify.py +292 -292
- package/md_cg/comment_gate.py +337 -337
- package/md_cg/cond_compose.py +190 -190
- package/md_cg/cond_facts.py +154 -154
- package/md_cg/cond_template.json +106 -106
- package/md_cg/condition_anchor.py +142 -142
- package/md_cg/conformance.py +726 -726
- package/md_cg/consistency.py +717 -717
- package/md_cg/consolidate.py +1537 -1439
- package/md_cg/corpus.py +110 -110
- package/md_cg/crosscheck.py +1098 -1097
- package/md_cg/crypto.py +3 -1
- package/md_cg/d_meta.py +310 -310
- package/md_cg/datapath.py +78 -18
- package/md_cg/docindex.py +473 -473
- package/md_cg/eval_common.py +575 -575
- package/md_cg/evidence.py +4 -2
- package/md_cg/evolution.py +477 -477
- package/md_cg/export.py +222 -220
- package/md_cg/forgetting.py +581 -581
- package/md_cg/fsutil.py +377 -329
- package/md_cg/hotcache.py +48 -7
- package/md_cg/hyperedge.py +251 -251
- package/md_cg/identity.py +390 -390
- package/md_cg/insight.py +500 -500
- package/md_cg/interop.py +338 -0
- package/md_cg/judgment_manifest.py +177 -0
- package/md_cg/lexicon/build_cedict_en_zh.py +329 -329
- package/md_cg/lexicon/build_standard_en.py +171 -171
- package/md_cg/lexicon/expand_en_zh.py +211 -211
- package/md_cg/lifecycle.py +272 -272
- package/md_cg/linkref.py +280 -280
- package/md_cg/links.py +140 -107
- package/md_cg/mcp_server.py +403 -55
- package/md_cg/md_whitebox.py +345 -345
- package/md_cg/mdcg.py +783 -233
- package/md_cg/mdcos.py +500 -70
- package/md_cg/metacognition.py +591 -591
- package/md_cg/migrate.py +119 -119
- package/md_cg/migrate_aeis.py +221 -221
- package/md_cg/migrate_roleplay.py +293 -293
- package/md_cg/migrate_wisdom_graph.py +360 -360
- package/md_cg/mreview/__init__.py +25 -25
- package/md_cg/mreview/__main__.py +110 -110
- package/md_cg/mreview/bundle.py +178 -178
- package/md_cg/mreview/candidates.py +262 -262
- package/md_cg/mreview/govern.py +694 -693
- package/md_cg/mreview/locate.py +939 -939
- package/md_cg/mreview/pipeline.py +728 -728
- package/md_cg/mreview/rules/duplication.json +21 -21
- package/md_cg/mreview/rules/field_coverage.json +54 -54
- package/md_cg/mreview/rules/source_license.json +21 -21
- package/md_cg/mreview/rules/template_flow.json +21 -21
- package/md_cg/mreview/ruleset.py +252 -252
- package/md_cg/nodefile.py +575 -575
- package/md_cg/pooling.py +484 -472
- package/md_cg/postings.py +300 -298
- package/md_cg/predict.py +1100 -1100
- package/md_cg/progressive.py +123 -123
- package/md_cg/protect.py +272 -272
- package/md_cg/protocol/md_cg_gate.proto +33 -33
- package/md_cg/protocol.py +372 -372
- package/md_cg/provenance.py +582 -582
- package/md_cg/reach.py +453 -453
- package/md_cg/readcache.py +143 -0
- package/md_cg/reconcile.py +228 -0
- package/md_cg/refindex.py +833 -833
- package/md_cg/refine.py +604 -604
- package/md_cg/review_cli.py +170 -0
- package/md_cg/roleviews.py +89 -89
- package/md_cg/routing.py +393 -365
- package/md_cg/run_tests.py +211 -0
- package/md_cg/scrub.py +13 -3
- package/md_cg/security.py +128 -18
- package/md_cg/self_state.py +1029 -1029
- package/md_cg/selfreport.py +152 -151
- package/md_cg/semantic/__init__.py +10 -10
- package/md_cg/semantic/canonical.py +122 -122
- package/md_cg/semantic/en_normalizer.py +364 -364
- package/md_cg/semantic/en_zh_map.json +28694 -0
- package/md_cg/semantic/export_en_zh_map.py +64 -0
- package/md_cg/semantic/unify.py +45 -0
- package/md_cg/semantic/zh_en_atoms.py +139 -139
- package/md_cg/signer.py +7 -4
- package/md_cg/sources.py +816 -582
- package/md_cg/statushdr.py +179 -179
- package/md_cg/stg.py +54 -37
- package/md_cg/subgraph.py +729 -729
- package/md_cg/sustain.py +35 -5
- package/md_cg/tasks.py +470 -470
- package/md_cg/test_access_hints.py +147 -0
- package/md_cg/test_action_derive.py +203 -203
- package/md_cg/test_audit_rotate.py +270 -270
- package/md_cg/test_autonomy.py +143 -143
- package/md_cg/test_bench_governance.py +102 -102
- package/md_cg/test_blindspot_tickets.py +166 -166
- package/md_cg/test_branch_discard_tombstone.py +136 -0
- package/md_cg/test_branches.py +13 -3
- package/md_cg/test_ccg_perturb.py +184 -184
- package/md_cg/test_ccgc.py +433 -433
- package/md_cg/test_census_prune.py +81 -81
- package/md_cg/test_chain_read_isolate.py +168 -0
- package/md_cg/test_cond_compose_anchors.py +76 -76
- package/md_cg/test_cond_match.py +165 -165
- package/md_cg/test_condition_anchor.py +81 -81
- package/md_cg/test_d_meta.py +412 -412
- package/md_cg/test_datapath_device_name.py +203 -0
- package/md_cg/test_datapath_root.py +199 -199
- package/md_cg/test_emit_negtail_cache.py +156 -0
- package/md_cg/test_en_pipeline.py +22 -2
- package/md_cg/test_gain_gate.py +212 -212
- package/md_cg/test_govern_directread.py +421 -0
- package/md_cg/test_health_scale.py +173 -173
- package/md_cg/test_hive_ingest.py +285 -0
- package/md_cg/test_hot_cold.py +215 -215
- package/md_cg/test_hyperedge.py +245 -245
- package/md_cg/test_i26_empty_first_write.py +116 -0
- package/md_cg/test_i27_e041_identity.py +128 -0
- package/md_cg/test_i28_hotcache_prodpath.py +122 -0
- package/md_cg/test_i32_hotcache_env_key.py +218 -0
- package/md_cg/test_identity_attribution.py +96 -15
- package/md_cg/test_index_durability.py +17 -3
- package/md_cg/test_interop.py +95 -0
- package/md_cg/test_interop_judgment.py +228 -0
- package/md_cg/test_issue39_utf8_stdio.py +273 -0
- package/md_cg/test_lifecycle.py +309 -309
- package/md_cg/test_linkref.py +306 -306
- package/md_cg/test_links_concurrent_write.py +188 -0
- package/md_cg/test_lock.py +43 -43
- package/md_cg/test_md_access_parity.py +255 -255
- package/md_cg/test_md_writepath.py +345 -345
- package/md_cg/test_mdstore_search_parity.py +160 -0
- package/md_cg/test_merge_upsert.py +168 -0
- package/md_cg/test_mr_m2.py +587 -587
- package/md_cg/test_mr_m3.py +710 -710
- package/md_cg/test_mr_m4.py +485 -485
- package/md_cg/test_n123_derive_expiry_chain.py +205 -0
- package/md_cg/test_n130_verify_falsified_protect.py +185 -0
- package/md_cg/test_n131_merge_gate.py +205 -0
- package/md_cg/test_p0.py +250 -250
- package/md_cg/test_p1.py +316 -316
- package/md_cg/test_p10_identity.py +173 -173
- package/md_cg/test_p11_consistency.py +233 -233
- package/md_cg/test_p12_metacognition.py +212 -212
- package/md_cg/test_p13_encryption.py +241 -241
- package/md_cg/test_p14_sustain.py +249 -249
- package/md_cg/test_p15_scrub.py +280 -280
- package/md_cg/test_p16_self_state.py +301 -301
- package/md_cg/test_p17_predict.py +354 -354
- package/md_cg/test_p18_whitebox.py +171 -171
- package/md_cg/test_p19_migrate_roleplay.py +149 -149
- package/md_cg/test_p1x_ref_root.py +160 -0
- package/md_cg/test_p20_evolution.py +315 -315
- package/md_cg/test_p21_tokens.py +293 -270
- package/md_cg/test_p22_theory.py +175 -175
- package/md_cg/test_p23_links.py +311 -311
- package/md_cg/test_p24_evidence.py +227 -227
- package/md_cg/test_p25_weights.py +156 -156
- package/md_cg/test_p26_refindex.py +416 -416
- package/md_cg/test_p27_docindex.py +16 -7
- package/md_cg/test_p28_refcheck.py +305 -305
- package/md_cg/test_p29_session_ingest_export.py +354 -333
- package/md_cg/test_p2_mcp.py +3 -0
- package/md_cg/test_p3.py +11 -2
- package/md_cg/test_p30_maintain.py +330 -330
- package/md_cg/test_p31_insight.py +534 -534
- package/md_cg/test_p32_backfill.py +7 -1
- package/md_cg/test_p33_ccg_wiring.py +293 -293
- package/md_cg/test_p34_crosscheck.py +331 -331
- package/md_cg/test_p35_conditioned_claim.py +252 -252
- package/md_cg/test_p36_kp_align.py +230 -230
- package/md_cg/test_p37_condition_space.py +248 -248
- package/md_cg/test_p38_concurrent_flush.py +102 -0
- package/md_cg/test_p38_contextualize.py +273 -273
- package/md_cg/test_p39_verify_flow.py +153 -0
- package/md_cg/test_p39_vision_evidence.py +369 -369
- package/md_cg/test_p40_refine_worklist.py +241 -241
- package/md_cg/test_p41_evolve_patrol.py +224 -224
- package/md_cg/test_p42_provenance.py +269 -269
- package/md_cg/test_p43_pooling.py +412 -398
- package/md_cg/test_p44_md_whitebox.py +231 -231
- package/md_cg/test_p45_session_identity.py +219 -219
- package/md_cg/test_p46_unit_scope.py +272 -272
- package/md_cg/test_p47_session_view.py +316 -0
- package/md_cg/test_p4_fuzzy.py +223 -223
- package/md_cg/test_p5_semantic.py +226 -226
- package/md_cg/test_p6_consolidate.py +440 -387
- package/md_cg/test_p7_goals_recent.py +202 -202
- package/md_cg/test_p8_subgraph_chain.py +200 -200
- package/md_cg/test_p9_forget_protect.py +231 -231
- package/md_cg/test_predict_beta.py +135 -135
- package/md_cg/test_preflight_failclosed.py +100 -100
- package/md_cg/test_progressive.py +146 -146
- package/md_cg/test_propose_tail_index.py +157 -0
- package/md_cg/test_protocol.py +243 -243
- package/md_cg/test_reach.py +378 -378
- package/md_cg/test_reach_keys.py +201 -201
- package/md_cg/test_read_clip.py +141 -141
- package/md_cg/test_read_scope_b27.py +277 -0
- package/md_cg/test_readcache_default_on.py +168 -0
- package/md_cg/test_readcache_precise_inval.py +270 -0
- package/md_cg/test_readcache_prodpath.py +203 -0
- package/md_cg/test_reconcile_v0.py +294 -0
- package/md_cg/test_retr_gates_prodpath.py +140 -0
- package/md_cg/test_retr_s1.py +344 -340
- package/md_cg/test_retr_s1b.py +276 -209
- package/md_cg/test_retr_s3.py +194 -194
- package/md_cg/test_retr_s4.py +163 -163
- package/md_cg/test_retr_s5.py +200 -200
- package/md_cg/test_retr_s6.py +157 -157
- package/md_cg/test_retr_s7.py +392 -384
- package/md_cg/test_retr_s8_time.py +369 -316
- package/md_cg/test_retr_s9_edges.py +286 -286
- package/md_cg/test_retr_s9_entity_ctx.py +9 -3
- package/md_cg/test_retr_score_once.py +208 -0
- package/md_cg/test_review_conformance.py +367 -367
- package/md_cg/test_review_onepass.py +170 -0
- package/md_cg/test_role_views.py +354 -354
- package/md_cg/test_rrf_graph_seed_cache.py +154 -0
- package/md_cg/test_security_audit.py +155 -0
- package/md_cg/test_security_audit_b26.py +161 -0
- package/md_cg/test_security_audit_v21.py +250 -0
- package/md_cg/test_sem_noise.py +242 -242
- package/md_cg/test_semantic_canonical.py +16 -2
- package/md_cg/test_session_isolation.py +168 -0
- package/md_cg/test_snapshot_autoclose.py +187 -0
- package/md_cg/test_subproc_encoding.py +192 -192
- package/md_cg/test_sustain_mutual.py +153 -153
- package/md_cg/test_tail_watermark_race.py +208 -0
- package/md_cg/test_tasks.py +409 -409
- package/md_cg/test_tenant_env_override_warn.py +139 -0
- package/md_cg/test_tenant_registry_corrupt_warn.py +151 -0
- package/md_cg/test_tool_face.py +189 -189
- package/md_cg/test_transfer.py +180 -180
- package/md_cg/test_trust.py +361 -361
- package/md_cg/test_twophase.py +286 -286
- package/md_cg/test_v14_fixes.py +38 -20
- package/md_cg/test_validity_filter.py +280 -280
- package/md_cg/test_verify_answer.py +138 -138
- package/md_cg/test_verify_dirty_reconcile.py +157 -0
- package/md_cg/test_wisdom_md_store.py +292 -292
- package/md_cg/test_writelimit.py +197 -197
- package/md_cg/test_writepipe.py +214 -214
- package/md_cg/theory.py +6 -3
- package/md_cg/tokens.py +85 -14
- package/md_cg/tool_face.py +260 -260
- package/md_cg/trust.py +986 -950
- package/md_cg/twophase.py +231 -231
- package/md_cg/units.py +668 -667
- package/md_cg/vision_evidence.py +667 -666
- package/md_cg/weights.py +624 -624
- package/md_cg/whitebox.py +527 -527
- package/md_cg/whitebox_kb/__init__.py +37 -37
- package/md_cg/whitebox_kb/aeis_core/__init__.py +42 -42
- package/md_cg/whitebox_kb/aeis_core/semantic.py +280 -280
- package/md_cg/whitebox_kb/aeis_core/textutil.py +13 -13
- package/md_cg/whitebox_kb/engine.py +310 -310
- package/md_cg/whitebox_kb/seed_knowledge//346/231/272/350/203/275/350/256/2723.4.md +5260 -5260
- package/md_cg/whitebox_kb/wisdom/browser_units.py +2631 -2631
- package/md_cg/whitebox_kb/wisdom/causal_discover.py +432 -432
- package/md_cg/whitebox_kb/wisdom/chat_engine.py +1506 -1506
- package/md_cg/whitebox_kb/wisdom/compiler_code_units.py +3033 -3033
- package/md_cg/whitebox_kb/wisdom/condition_algebra.py +112 -112
- package/md_cg/whitebox_kb/wisdom/condition_frame.py +315 -315
- package/md_cg/whitebox_kb/wisdom/condition_kb.py +108 -108
- package/md_cg/whitebox_kb/wisdom/conflict_map.json +4445 -4445
- package/md_cg/whitebox_kb/wisdom/core/lexer.py +512 -512
- package/md_cg/whitebox_kb/wisdom/core/name_checker.py +1023 -1023
- package/md_cg/whitebox_kb/wisdom/cspmn.py +258 -258
- package/md_cg/whitebox_kb/wisdom/csre.py +264 -264
- package/md_cg/whitebox_kb/wisdom/danmaku_audit.py +252 -252
- package/md_cg/whitebox_kb/wisdom/distilled_condition_units.json +6417 -6417
- package/md_cg/whitebox_kb/wisdom/docs/WB-EVAL-20260902b.json +1950 -1950
- package/md_cg/whitebox_kb/wisdom/docs/WB-EVAL-20260902c.json +1296 -1296
- package/md_cg/whitebox_kb/wisdom/docs/whitebox_capability_graph_demo.json +59 -59
- package/md_cg/whitebox_kb/wisdom/graph_db_units.py +3089 -3089
- package/md_cg/whitebox_kb/wisdom/knowledge_points.py +318 -318
- package/md_cg/whitebox_kb/wisdom/md_access.py +470 -470
- package/md_cg/whitebox_kb/wisdom/md_store.py +276 -251
- package/md_cg/whitebox_kb/wisdom/migrate_wisdom.py +476 -476
- package/md_cg/whitebox_kb/wisdom/multilang_ir.py +128 -124
- package/md_cg/whitebox_kb/wisdom/navigate.py +248 -248
- package/md_cg/whitebox_kb/wisdom/neural_retrieve.py +224 -224
- package/md_cg/whitebox_kb/wisdom/os_units.py +2735 -2735
- package/md_cg/whitebox_kb/wisdom/pattern_separation.py +376 -376
- package/md_cg/whitebox_kb/wisdom/prereq_map.json +364 -364
- package/md_cg/whitebox_kb/wisdom/python_code_units.py +2766 -2766
- package/md_cg/whitebox_kb/wisdom/role_solidified.json +7 -7
- package/md_cg/whitebox_kb/wisdom/route_memory.py +244 -244
- package/md_cg/whitebox_kb/wisdom/scene_reconstruction.py +148 -148
- package/md_cg/whitebox_kb/wisdom/snr_report.json +40 -40
- package/md_cg/whitebox_kb/wisdom/test_code_compose_domains.py +7541 -7541
- package/md_cg/whitebox_kb/wisdom/test_compiler_self_bootstrap.py +354 -354
- package/md_cg/whitebox_kb/wisdom/test_ecosystem_assembly.py +158 -158
- package/md_cg/whitebox_kb/wisdom/test_ecosystem_demos.py +193 -193
- package/md_cg/whitebox_kb/wisdom/test_graph_db.py +292 -292
- package/md_cg/whitebox_kb/wisdom/test_python_self_bootstrap.py +160 -160
- package/md_cg/whitebox_kb/wisdom/trigger_words_index.json +4366 -4366
- package/md_cg/whitebox_kb/wisdom/verifier.py +1297 -1297
- package/md_cg/writelimit.py +356 -356
- package/md_cg/writepipe.py +20 -8
- package/package.json +101 -96
- package/skills/plugin.json +54 -54
- package/skills/skills/designer-perspective/SKILL.md +158 -158
- package/skills/skills/designer-perspective/references/01-observation-position.md +66 -66
- package/skills/skills/designer-perspective/references/02-structure-recognition.md +62 -62
- package/skills/skills/designer-perspective/references/03-direction-judgment.md +55 -55
- package/skills/skills/designer-perspective/references/04-qualification-verdict.md +72 -72
- package/skills/skills/designer-perspective/references/05-condition-attribution.md +74 -74
- package/skills/skills/designer-perspective/scripts/designer.py +545 -545
- package/skills/skills/designer-perspective/tests/cases.jsonl +17 -17
- package/skills/skills/designer-perspective/tests/selftest.py +61 -61
- package/skills/skills/lingshu-browser/SKILL.md +60 -60
- package/skills/skills/lingshu-compiler/SKILL.md +56 -56
- package/skills/skills/lingshu-compiler/units/analyze-type-infer/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/check-name-real/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-assign/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-expr-tree/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-full-pipeline/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-func-def/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-if-then/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-logic-expr/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-recursive/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-scope/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-type-check/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-while/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0010c4bf/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0355bffb/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0361708a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-054a0414/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-05a1691a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-05eeed1e/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0622a1f6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-08b54217/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0a62b70c/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0ab24d00/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0e093688/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0e82b966/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0ee9b9b9/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0f3787e6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-1028685f/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-11897630/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-16661b9b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-1f722303/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-25be1262/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2a76ba07/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2dbea54a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2df52f16/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2ec2c9d2/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2f8c8f39/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-38378ac7/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-39457d2e/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-39fb5926/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-47f4fbfa/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4a8cd1f1/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4b230b6b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4cbbda95/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4d5a68ff/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-56dc9bdd/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-57e76ebe/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-61ff016b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-63eae588/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-64c4224b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-66377955/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-674ab4f6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6af76fd6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6d979db2/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6de326c0/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6f1c0eea/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-724d6c9b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-7690177f/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-7b229a7d/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-7f471b3a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-815cad08/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-83c61634/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-8c798c81/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-8dd747ac/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-90324d0a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-94b8d72d/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-94f12231/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-95937c16/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-98a5625b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-98b4c42f/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-98e3894a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-9bdfe4b8/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-9d9b4e83/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-9f7be5ad/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-a6daf076/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-a7995a0c/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-a8399248/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-aabbd099/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-afe169d8/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b0678bda/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b09bd196/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b1396e23/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b9b31ce0/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-c10264a7/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-cb1e8e4b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-ccafd438/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-cda9c262/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-ce648068/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-cf5776a4/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-d974e5d3/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-e3979fd3/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-eb1cf2b5/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-ecb30d5b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-f8c8b24b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-f99fedbe/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-fa8ff5f7/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-fe1b058d/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/lex-chinese-program/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/lex-dao-de-jing/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/lex-nine-chapters/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-arithmetic/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-array-ops/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-closure-call/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-closure-create/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-compare/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-cond-jump/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-cond-space/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-exception/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-func-call/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-loop-run/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-profiling/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-refcount/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-run-loop/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-short-circuit/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-stack-guard/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-stack-ops/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-trust-accum/SKILL.md +45 -45
- package/skills/skills/lingshu-graph/SKILL.md +63 -63
- package/skills/skills/lingshu-net/SKILL.md +48 -48
- package/skills/skills/lingshu-os/SKILL.md +64 -64
- package/skills/skills/lingshu-pylang/SKILL.md +71 -71
- package/src/bridge.ts +33 -0
- package/src/hooks.ts +38 -2
- package/src/index.ts +526 -518
- package/src/lib/datapath.ts +326 -326
- package/src/lib/mdcg_client.ts +413 -413
- package/src/lib/mutual.ts +428 -428
- package/src/lib/prompt_safety.ts +62 -62
- package/src/lib/python_path.ts +71 -71
- package/src/lib/roleplay_web.ts +116 -29
- package/src/lib/token_store.ts +13 -3
- package/src/tools.ts +212 -212
- package/zcode/AGENTS.md +11 -3
- package/zcode/README.md +41 -41
- /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
package/md_cg/mdcos.py
CHANGED
|
@@ -30,13 +30,13 @@ from .mdcg import (MdCG, expand_query_terms, bigrams, normalize_en, STATE_ACCEPT
|
|
|
30
30
|
TIER_BUCKET_SCAN, TIER_GLOBAL_LIKE, TIER_GLOBAL_SCAN,
|
|
31
31
|
GLOBAL_CAP, expand_query_terms_weighted,
|
|
32
32
|
expand_query_terms_llm, en_zh_bigrams, semantic_on,
|
|
33
|
-
cut_by_relevance)
|
|
33
|
+
cut_by_relevance, apply_retrieval_gates)
|
|
34
34
|
from . import (nodefile, routing, chain, subgraph, forgetting, protect,
|
|
35
35
|
identity, consistency, metacognition, crypto, sustain,
|
|
36
36
|
self_state, predict, evolution, weights, pooling,
|
|
37
37
|
writelimit, reach, trust, roleviews)
|
|
38
38
|
from .fsutil import (FileLock, atomic_write, append_jsonl, read_jsonl,
|
|
39
|
-
count_jsonl)
|
|
39
|
+
read_jsonl_tail, count_jsonl, publish)
|
|
40
40
|
from .security import (Principal, TenantRegistry, AccessDenied,
|
|
41
41
|
SENSITIVITY_ORDER, DEFAULT_SENSITIVITY, _rank)
|
|
42
42
|
|
|
@@ -326,6 +326,46 @@ class MdCGOS(MdCG):
|
|
|
326
326
|
os.makedirs(self.trash_dir, exist_ok=True)
|
|
327
327
|
self._audit_writes = 0 # 进程内写入计数(轮转探测节流,稳态零 stat)
|
|
328
328
|
self._audit_index = None # 归档索引缓存(懒加载)
|
|
329
|
+
# 审核队列增量对账缓存(issue #32):inbox/decisions 均为 append-only
|
|
330
|
+
# (写点全在 strict 锁内经 append_jsonl,无轮转/截断),propose 的
|
|
331
|
+
# 幂等对账从「每条全量重读 O(M+D)」改为「stat 尾部增量」——跨进程
|
|
332
|
+
# append 由 stat 自动并入,无需显式失效。
|
|
333
|
+
self._inbox_idx = {} # phash → [(pid, node_id)] 文件序
|
|
334
|
+
self._inbox_idx_size = -1 # 已并入的 inbox 字节偏移(扫描水位)
|
|
335
|
+
self._inbox_idx_mtime = -1
|
|
336
|
+
self._pid_st = {} # pid → 最新裁决记录
|
|
337
|
+
self._pid_st_size = -1 # 已并入的 decisions 字节偏移
|
|
338
|
+
self._pid_st_mtime = -1
|
|
339
|
+
# review 治理面全记录增量缓存(issue #35):review_stats/review_list/
|
|
340
|
+
# review_decide/_cascade_dedup/verify_review_record 单次调用内曾各自
|
|
341
|
+
# 全量重读同一 jsonl(inbox 2 遍 + decisions 1-4 遍)——改为 stat 尾部
|
|
342
|
+
# 增量的全记录缓存(与 _pid_status 同款对账),调用方内存线性扫。
|
|
343
|
+
# 注意:缓存列表为内部状态,调用方只读不得变更。
|
|
344
|
+
self._inbox_recs = [] # inbox 全记录(文件序)
|
|
345
|
+
self._inbox_recs_size = -1
|
|
346
|
+
self._inbox_recs_mtime = -1
|
|
347
|
+
self._dec_recs = [] # decisions 全记录(文件序)
|
|
348
|
+
self._dec_recs_size = -1
|
|
349
|
+
self._dec_recs_mtime = -1
|
|
350
|
+
# 热缓存挂载(issue #28,2026-09-23):读侧(search_rrf)与失效侧
|
|
351
|
+
# (writepipe)早已接好,唯独无人调 attach——生产恒 None,重复 query
|
|
352
|
+
# 无法命中。默认关(env 未设 → get(self) 恒 None,零变更纪律);
|
|
353
|
+
# MDCG_HOTCACHE=1 显式启用,容量经 MDCG_HOTCACHE_MAX_NODES/MAX_QUERIES
|
|
354
|
+
# 可配(缺省 256 对 567 节点级库会持续 LRU 淘汰,大库请调大)。
|
|
355
|
+
if os.environ.get("MDCG_HOTCACHE") == "1":
|
|
356
|
+
from . import hotcache as _hc
|
|
357
|
+
_hc.attach(self)
|
|
358
|
+
# 检索读缓存挂载(issue #31 P2,批次 21):MdStore 理论落地——节点
|
|
359
|
+
# 文件解析产物常驻(567 池实测 572 次 open/查询 → 缓存后 ~0),写失
|
|
360
|
+
# 效走 _dirty 代际哨兵(所有写路径必然标脏,无漏挂面)。
|
|
361
|
+
# 默认**开**(issue #31 后续修复):生产检索入口(本类 search →
|
|
362
|
+
# _read_many)默认态每查询全池 open+2×realpath+frontmatter 解析,
|
|
363
|
+
# 3300 池实测 ~602ms/查询、万级外推 ~2s+(O(n) 线性);开关早已
|
|
364
|
+
# 存在但默认关 → 生产恒不装配。MDCG_READ_CACHE=0 显式关闭(opt-out
|
|
365
|
+
# 退出阀:跨进程改写须本进程立即可见 / 内存受限的部署回到旧行为)。
|
|
366
|
+
from . import readcache as _rc
|
|
367
|
+
if _rc.enabled():
|
|
368
|
+
_rc.install(self)
|
|
329
369
|
|
|
330
370
|
# ================= 6. payload-free 审计 =================
|
|
331
371
|
|
|
@@ -442,7 +482,7 @@ class MdCGOS(MdCG):
|
|
|
442
482
|
name = "_audit.%06d.jsonl" % self._next_shard_seq()
|
|
443
483
|
dst = os.path.join(self.audit_archive, name)
|
|
444
484
|
try:
|
|
445
|
-
|
|
485
|
+
publish(self.audit_log, dst) # Windows 短重试:AV 短锁不误判抢输
|
|
446
486
|
except OSError:
|
|
447
487
|
return None # 抢输(文件已被移走)→ 让位,不报错
|
|
448
488
|
scale = self._audit_count_shard(dst, size) # 分档:有界扫描 / 只读量级
|
|
@@ -565,10 +605,22 @@ class MdCGOS(MdCG):
|
|
|
565
605
|
"""在父类 add 之上:写入 role(frontmatter + 索引),默认 role=None(知识)。"""
|
|
566
606
|
if role is not None:
|
|
567
607
|
kw["role"] = role
|
|
608
|
+
# 会话归属必须落 frontmatter:本文件 session 过滤的文档即写「frontmatter.session,
|
|
609
|
+
# 写入时自动落盘」,但父类 add 的 fm 固定字典里没有该键、_stage 只把它放进索引 →
|
|
610
|
+
# 实际只有索引带归属,任何 rebuild_index() 都会抹掉(实测 73 节点里 56 个无
|
|
611
|
+
# frontmatter.session,而 _audit.jsonl 的 add 事件却 152/152 都记了 session:
|
|
612
|
+
# 写入口径与落盘口径脱钩)。与 role 同款:显式给就尊重,否则取 self.session
|
|
613
|
+
# (MdCGSecure 由 principal.session 注入,mcp_server 按请求切换 cg.session)。
|
|
614
|
+
_sess = kw.get("session") or getattr(self, "session", None)
|
|
615
|
+
if _sess and not kw.get("session"):
|
|
616
|
+
kw["session"] = _sess
|
|
568
617
|
nid = super().add(node_id, content, layer=layer, **kw)
|
|
569
618
|
e = self.index["nodes"].get(nid)
|
|
570
619
|
if e is not None and role is not None:
|
|
571
620
|
e["role"] = role
|
|
621
|
+
if e is not None and _sess:
|
|
622
|
+
e["session"] = _sess
|
|
623
|
+
if e is not None and (role is not None or _sess):
|
|
572
624
|
self._dirty[nid] = e
|
|
573
625
|
self._audit("add", nid, layer=layer, role=role,
|
|
574
626
|
payload_hash=_sig(content))
|
|
@@ -608,7 +660,8 @@ class MdCGOS(MdCG):
|
|
|
608
660
|
for e in self.index["nodes"].values():
|
|
609
661
|
if e.get("layer") in ("rejected", "unresolved", "goals"):
|
|
610
662
|
continue # 负记忆走覆盖标记;目标只做定向,都不进正排
|
|
611
|
-
|
|
663
|
+
# '"*"' = 显式跨会话(读遍所有会话);缺省 None 同义(见 stg.timeline)
|
|
664
|
+
if session and session != "*" and e.get("session") != session:
|
|
612
665
|
continue
|
|
613
666
|
if e.get("branch_id") not in (None, branch):
|
|
614
667
|
continue
|
|
@@ -705,6 +758,10 @@ class MdCGOS(MdCG):
|
|
|
705
758
|
详见 _candidates。
|
|
706
759
|
"""
|
|
707
760
|
q = (query or "").strip()
|
|
761
|
+
# 批次 15 统一口径(unify.py):任意语言 query → 标准原子序列;
|
|
762
|
+
# 与 MdCG.search/search_rrf 三入口同口径(MDCG_UNIFY_QUERY=0 可关)
|
|
763
|
+
from .semantic.unify import unify_query
|
|
764
|
+
q = unify_query(q)
|
|
708
765
|
if not q:
|
|
709
766
|
return [], {"tier": None, "reason": "empty_query", "scanned": 0}
|
|
710
767
|
pool_cfg = pooling.resolve(pooling.from_env(pools))
|
|
@@ -738,13 +795,34 @@ class MdCGOS(MdCG):
|
|
|
738
795
|
if context is not None:
|
|
739
796
|
ctx = context if isinstance(context, dict) else {}
|
|
740
797
|
route_bucket = routing.bucket_dir(routing.route_key(ctx, ctx.get("tags")))
|
|
798
|
+
# 与 MdCG.search 同一纪律(X2):无域信号时不施加桶约束,否则 route_key
|
|
799
|
+
# 回落的 orphan 会被当成真桶,下面 T0/T1 阶段读到该桶并因 valid>=min_results
|
|
800
|
+
# 直接 return,**全量阶梯永不执行** —— 标了 domain: 的节点整片不可见。
|
|
801
|
+
# 本覆写才是生产路径(MdCGSecure → 本类):缺此条则 MCP 端依旧丢召回。
|
|
802
|
+
if route_bucket == routing.ORPHAN:
|
|
803
|
+
route_bucket = None
|
|
741
804
|
big_domain = routing.big_domain_classify(terms)
|
|
742
805
|
big_scores = routing.big_domain_score_breakdown(terms)
|
|
806
|
+
# S1/S1b/S2 收敛 + S4 审计——与 MdCG.search 共享同一实现(issue #25:
|
|
807
|
+
# 本覆写此前完全不含门控,生产路径(MdCGSecure → 本类)从未生效——
|
|
808
|
+
# 开关显式打开也不生效、gates 审计不出现、scanned 恒全表)。
|
|
809
|
+
# 收敛在 _read_many 之前 → scanned 真实下降;gates 非空才落键
|
|
810
|
+
# (默认关时 meta 键集合与改动前逐字节一致,零变更纪律)。
|
|
811
|
+
entries, gates = apply_retrieval_gates(
|
|
812
|
+
entries, terms, big_domain, context, min_results)
|
|
813
|
+
if gates:
|
|
814
|
+
stat["gates"] = gates
|
|
743
815
|
neg_coverage = self._neg_coverage(terms) if include_neg else []
|
|
744
816
|
|
|
745
|
-
#
|
|
746
|
-
def try_stage(docs, tier):
|
|
747
|
-
|
|
817
|
+
# 生效条件:scored 为 None 时对 docs 调 self._score(docs, q, qb, pool_cfg),非 None 时直接以之为打分结果;分数 >0 的条数达到(search 作用域内的)min_results 就返回 self._emit(scored, k, tier, stat, route_bucket, record, len(docs), ...),否则返回 None。
|
|
818
|
+
def try_stage(docs, tier, scored=None):
|
|
819
|
+
# P2-4 回移(v7 N51 留档修复,缺陷迭代第 14 轮):支持传入已打分
|
|
820
|
+
# 结果——此前 T2/T3 均为「打分截断后又对 picked 重打」(600 池实测
|
|
821
|
+
# _score 4 调 [0,0,600,500]=1100 文档,500/1100≈45% 冗余)。与基类
|
|
822
|
+
# try_stage(mdcg.py P2-4,批次 31)同模板;_score 在单次 search 内
|
|
823
|
+
# 是纯函数(docs/q/qb/pool_cfg 均不变),透传不改变任何分值与输出。
|
|
824
|
+
if scored is None:
|
|
825
|
+
scored = self._score(docs, q, qb, pool_cfg)
|
|
748
826
|
valid = sum(1 for _, s in scored if s > 0)
|
|
749
827
|
if valid >= min_results:
|
|
750
828
|
return self._emit(scored, k, tier, stat, route_bucket, record,
|
|
@@ -752,6 +830,22 @@ class MdCGOS(MdCG):
|
|
|
752
830
|
big_domain, big_scores, pool_cfg)
|
|
753
831
|
return None
|
|
754
832
|
|
|
833
|
+
def _prescored(docs, scored_all):
|
|
834
|
+
"""P2-4 透传形态:按 node_id 键表把 docs 映射回已打分的
|
|
835
|
+
(card, score) 原对(恰为 _score 对该 docs 的输出,picked 序)。
|
|
836
|
+
|
|
837
|
+
键口径:scored 元素是 (card, score),card["id"] = fm.get("id")
|
|
838
|
+
or e["path"],恰为 doc_key(doc)[0](V21-6 取 [0] 作键同源)——
|
|
839
|
+
**不可**对 scored 元素调 pooling.doc_key(其形参是 (entry, fm,
|
|
840
|
+
content) 三元组;基类 reach 分支旧模板即此形态错误,MDCG_REACH=1
|
|
841
|
+
时 KeyError: 1,见 mdcg.py 同修)。**不可**自组 (doc, score) 对
|
|
842
|
+
(_emit 排序键读 x[0]["frontmatter"],x[0] 须是 card dict)。
|
|
843
|
+
docs 必为 scored_all 的子序列(cut_by_relevance 只选不造),
|
|
844
|
+
键表必命中。
|
|
845
|
+
"""
|
|
846
|
+
smap = {c.get("id"): (c, s) for c, s in scored_all}
|
|
847
|
+
return [smap[pooling.doc_key(d)[0]] for d in docs]
|
|
848
|
+
|
|
755
849
|
if route_bucket:
|
|
756
850
|
in_bucket = [e for e in entries if e.get("bucket") == route_bucket]
|
|
757
851
|
if in_bucket:
|
|
@@ -790,11 +884,15 @@ class MdCGOS(MdCG):
|
|
|
790
884
|
stat["cap"] = GLOBAL_CAP
|
|
791
885
|
# 与 T2 **无条件**同序调用(不可按 cap 短路:cut_by_relevance 还会写
|
|
792
886
|
# 池账 pool_taken/cands/lost,短路会让 meta.pools.taken 缺失 → test_p43(13) 红)
|
|
793
|
-
|
|
887
|
+
scored_r = self._score(hits_r, q, qb, pool_cfg)
|
|
888
|
+
hits_r, _rep = cut_by_relevance(hits_r, scored_r,
|
|
794
889
|
GLOBAL_CAP, pools=pool_cfg,
|
|
795
890
|
key_of=pooling.doc_key, stat=stat)
|
|
796
891
|
pooling.record_audit(stat, _rep)
|
|
797
|
-
|
|
892
|
+
# P2-4:打分结果经 scored 透传,不再对同一 hits_r 二次 _score
|
|
893
|
+
# (与基类 reach 分支同模板)。
|
|
894
|
+
out = try_stage(hits_r, TIER_GLOBAL_LIKE,
|
|
895
|
+
scored=_prescored(hits_r, scored_r))
|
|
798
896
|
if out:
|
|
799
897
|
return out
|
|
800
898
|
# 收敛阶段未产出结果 → 继续走下方全量 T2/T3;此时必须**改写 reach 审计**,
|
|
@@ -815,22 +913,27 @@ class MdCGOS(MdCG):
|
|
|
815
913
|
or (semantic_on() and d[1].get("semantic"))]
|
|
816
914
|
stat["pre_cap"] = len(hits)
|
|
817
915
|
stat["cap"] = GLOBAL_CAP
|
|
818
|
-
|
|
916
|
+
scored_h = self._score(hits, q, qb, pool_cfg)
|
|
917
|
+
hits, _rep = cut_by_relevance(hits, scored_h,
|
|
819
918
|
GLOBAL_CAP, pools=pool_cfg,
|
|
820
919
|
key_of=pooling.doc_key, stat=stat)
|
|
821
920
|
pooling.record_audit(stat, _rep)
|
|
822
|
-
|
|
921
|
+
# P2-4:截断打分结果透传,T2 腿不再对 hits 二次 _score。
|
|
922
|
+
out = try_stage(hits, TIER_GLOBAL_LIKE,
|
|
923
|
+
scored=_prescored(hits, scored_h))
|
|
823
924
|
if out:
|
|
824
925
|
return out
|
|
825
926
|
|
|
826
927
|
stat["pre_cap"] = len(docs_all)
|
|
827
928
|
stat["cap"] = GLOBAL_CAP
|
|
828
|
-
|
|
829
|
-
|
|
929
|
+
scored_a = self._score(docs_all, q, qb, pool_cfg)
|
|
930
|
+
picked, _rep = cut_by_relevance(docs_all, scored_a,
|
|
830
931
|
GLOBAL_CAP, pools=pool_cfg,
|
|
831
932
|
key_of=pooling.doc_key, stat=stat)
|
|
832
933
|
pooling.record_audit(stat, _rep)
|
|
833
|
-
|
|
934
|
+
# P2-4:T3 不再对 picked 重打(600 池实测此腿冗余 500 文档/查询,
|
|
935
|
+
# GLOBAL_CAP=500 截断后 picked ⊆ docs_all,键表回填即得终榜打分)。
|
|
936
|
+
scored = _prescored(picked, scored_a)
|
|
834
937
|
return self._emit(scored, k, TIER_GLOBAL_SCAN, stat, route_bucket,
|
|
835
938
|
record, len(picked), judge,
|
|
836
939
|
context, neg_coverage, big_domain, big_scores, pool_cfg)
|
|
@@ -886,6 +989,16 @@ class MdCGOS(MdCG):
|
|
|
886
989
|
return []
|
|
887
990
|
ctx = context if isinstance(context, dict) else {}
|
|
888
991
|
b = routing.bucket_dir(routing.route_key(ctx, ctx.get("tags")))
|
|
992
|
+
# 「无域信号」等价于「没声明条件」:条件桶路此时必须**弃权**,不能把
|
|
993
|
+
# route_key 回落的 orphan 当成一个真桶去硬过滤——否则凡是被标了 domain:
|
|
994
|
+
# (因而落在 cond_* 目录)的节点,对这条查询就整片不可见。
|
|
995
|
+
# 实测(带 context 但不含 domain / observation_position):弃权前只扫
|
|
996
|
+
# orphan 桶 10 个节点、目标节点召回丢失(T1_bucket_scan/scanned=10);
|
|
997
|
+
# 弃权后由词法/实体/图路正常召回(T2_global_like/scanned=75)。
|
|
998
|
+
# 与上面 context is None 的既有早返回同构,也贴合 test_p0 的
|
|
999
|
+
# 「桶路由平均 recall@10 ≥ 0.9(加 context 不丢召回)」不变量。
|
|
1000
|
+
if b == routing.ORPHAN:
|
|
1001
|
+
return []
|
|
889
1002
|
inb = [e for e in entries if e.get("bucket") == b]
|
|
890
1003
|
if not inb:
|
|
891
1004
|
return []
|
|
@@ -910,7 +1023,7 @@ class MdCGOS(MdCG):
|
|
|
910
1023
|
"content": c, "path": e["path"]}, 1.0))
|
|
911
1024
|
return out
|
|
912
1025
|
|
|
913
|
-
# 生效条件:当 seeds 非空时,仅取前 5
|
|
1026
|
+
# 生效条件:当 seeds 非空时,仅取前 5 个种子,种子的 edges 取法为:其 id 在 entries 的 path 文件名映射(by_id)中时经 self._read(e_seed) 读 frontmatter(读缓存覆盖——get 裸 open 不在缓存包装面),不在映射中(fm.id≠文件名等形态)时回落 self.get(n["id"])(旧口径,冷路径);从 edges 取 target(dict 取 target,否则 str(edge)),若 target 在 entries 映射中且不在 seed_ids 中则读取并追加分数 s*0.5;seeds 为空返回 [];depth 默认 1 但本段未使用;
|
|
914
1027
|
def _path_graph(self, query, entries, seeds, depth=1):
|
|
915
1028
|
"""图扩展路径:从词法种子沿 edges 一跳扩展。"""
|
|
916
1029
|
if not seeds:
|
|
@@ -922,10 +1035,24 @@ class MdCGOS(MdCG):
|
|
|
922
1035
|
by_id[nid] = e
|
|
923
1036
|
out = []
|
|
924
1037
|
for n, s in seeds[:5]:
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1038
|
+
# 种子读改走 self._read(v9:92/v13 留档修复,缺陷迭代第 14 轮):
|
|
1039
|
+
# get 裸 open+nodefile.loads,不在 readcache.install 的包装面
|
|
1040
|
+
#(只包 cg._read)——search_rrf 默认 paths 含 graph,每查询固定
|
|
1041
|
+
# ≤5 次盘读(40 池实测 Q2 增量恰 5,graph 零产出也在边循环前
|
|
1042
|
+
# 发生);边目标(下方 self._read)早已同形。种子只要 frontmatter
|
|
1043
|
+
# 的 edges(content 不解封不用),种子来自 lexical(entries/
|
|
1044
|
+
# _candidates 派生,MdCGSecure._candidates 已过 _readable)——
|
|
1045
|
+
# 绕过 get 的读隔离门无损失,图路扩展产物本由
|
|
1046
|
+
# MdCGSecure.search_rrf 终态二次过滤兜底。by_id 不含(fm.id≠
|
|
1047
|
+
# 文件名等形态)回落 get 保旧口径。
|
|
1048
|
+
e_seed = by_id.get(n["id"])
|
|
1049
|
+
if e_seed is not None:
|
|
1050
|
+
fm_s, _c = self._read(e_seed)
|
|
1051
|
+
edges = (fm_s or {}).get("edges") or []
|
|
1052
|
+
else:
|
|
1053
|
+
node = self.get(n["id"])
|
|
1054
|
+
edges = ((node or {}).get("frontmatter") or {}).get("edges") or []
|
|
1055
|
+
for edge in edges:
|
|
929
1056
|
tid = edge.get("target") if isinstance(edge, dict) else str(edge)
|
|
930
1057
|
if tid in by_id and tid not in seed_ids:
|
|
931
1058
|
e = by_id[tid]
|
|
@@ -1175,6 +1302,10 @@ class MdCGOS(MdCG):
|
|
|
1175
1302
|
串结果);候选层语义与 search 一致,详见 _candidates。
|
|
1176
1303
|
"""
|
|
1177
1304
|
q = (query or "").strip()
|
|
1305
|
+
# 批次 15 统一口径(unify.py):任意语言 query → 标准原子序列;
|
|
1306
|
+
# 归一后的 q 进热路径缓存键(归一确定 → 缓存不串味)
|
|
1307
|
+
from .semantic.unify import unify_query
|
|
1308
|
+
q = unify_query(q)
|
|
1178
1309
|
if not q:
|
|
1179
1310
|
return [], {"tier": None, "reason": "empty_query", "paths": {}}
|
|
1180
1311
|
# 热路径:query 结果缓存命中即返回(不改 RRF 核心)
|
|
@@ -1195,6 +1326,9 @@ class MdCGOS(MdCG):
|
|
|
1195
1326
|
"judge": bool(judge), "judge_ranking": bool(judge_ranking),
|
|
1196
1327
|
"goal_text": goal_text, "context": context,
|
|
1197
1328
|
"early_stop_threshold": early_stop_threshold,
|
|
1329
|
+
# 进程级开关也改口径(v14 只补了参数面):MDCG_SEMANTIC /
|
|
1330
|
+
# MDCG_EN_ATOMS / MDCG_UNIFY_QUERY 等不入键即跨口径命中(2026-09-24 修复)。
|
|
1331
|
+
"env_switch": _hc.env_switch_key(),
|
|
1198
1332
|
}
|
|
1199
1333
|
# 不可稳定进键的参数(自定义可调用 query_expand):非默认即**绕行**
|
|
1200
1334
|
# 缓存(读+写双侧闭合)——fail-closed,宁可不用缓存也不串味。
|
|
@@ -1485,15 +1619,24 @@ class MdCGOS(MdCG):
|
|
|
1485
1619
|
|
|
1486
1620
|
# ================= 1. Fix pairs 自动挖掘 =================
|
|
1487
1621
|
|
|
1488
|
-
# 生效条件:当 events 传入时,兼容显式 {error,fix} 对与含 text 的事件序列;后者在错误行长度 >= min_len 后向后 lookahead 条内寻找 _FIX_RE 命中的行配对并 break
|
|
1489
|
-
def mine_fix_pairs(self, events, lookahead: int = 4, min_len: int = 6
|
|
1622
|
+
# 生效条件:当 events 传入时,兼容显式 {error,fix} 对与含 text 的事件序列;后者在错误行长度 >= min_len 后向后 lookahead 条内寻找 _FIX_RE 命中的行配对并 break;去重后为每对产出修复知识(as_proposals 为假→add 直写 knowledge 层;为真→propose 入审核队列,判据指纹随提案落盘,knowledge_ids 为空、pids 收提案 id 并附 as_proposals=True)与 add_rejected 负记忆,返回 pairs/rejected_ids/knowledge_ids(提案模式另附 pids);
|
|
1623
|
+
def mine_fix_pairs(self, events, lookahead: int = 4, min_len: int = 6,
|
|
1624
|
+
as_proposals: bool = False):
|
|
1490
1625
|
"""从行为日志挖掘「错误 → 修复」对。
|
|
1491
1626
|
|
|
1492
1627
|
events: [{"role": ..., "text": ...}] 或 [{"error":..., "fix":...}](显式对)
|
|
1493
1628
|
返回 {"pairs": [...], "rejected_ids": [...], "knowledge_ids": [...]}
|
|
1494
1629
|
|
|
1630
|
+
as_proposals=False(默认,显式调用语义):正记忆直写 knowledge 层——
|
|
1631
|
+
调用方是有意图的显式动作(如 mdcg_mine_fix_pairs 工具直调)。
|
|
1632
|
+
as_proposals=True(自动管线语义):正记忆改走 propose 审核队列——
|
|
1633
|
+
自动产物不经收口不入知识层(§5.5 系统纪律化,zcode 外评 break#2);
|
|
1634
|
+
判据指纹随提案落盘,复核者只能按原判据裁决不能放宽;payload_hash
|
|
1635
|
+
幂等(重试与崩溃恢复无害)。负记忆一律直写 rejected 层(隔离层,
|
|
1636
|
+
不存在 knowledge 污染问题)。
|
|
1637
|
+
|
|
1495
1638
|
产出:
|
|
1496
|
-
· knowledge/<fix_xxx>.md —— 可路由的修复知识(CCG 5 要素)
|
|
1639
|
+
· knowledge/<fix_xxx>.md 或审核队列提案 —— 可路由的修复知识(CCG 5 要素)
|
|
1497
1640
|
· rejected/<rej_xxx>.md —— 负记忆「此错误不必深挖根因」(防重复踩坑)
|
|
1498
1641
|
"""
|
|
1499
1642
|
pairs = []
|
|
@@ -1528,7 +1671,7 @@ class MdCGOS(MdCG):
|
|
|
1528
1671
|
seen.add(k)
|
|
1529
1672
|
uniq.append((err, fix))
|
|
1530
1673
|
|
|
1531
|
-
rej_ids, kno_ids = [], []
|
|
1674
|
+
rej_ids, kno_ids, pids = [], [], []
|
|
1532
1675
|
for err, fix in uniq:
|
|
1533
1676
|
# 1) 可路由的修复知识
|
|
1534
1677
|
kid = "fix_" + _sig(err + "\x00" + fix)
|
|
@@ -1540,17 +1683,31 @@ class MdCGOS(MdCG):
|
|
|
1540
1683
|
f"# 验证方式:行为日志(后续同类错误不再出现)\n"
|
|
1541
1684
|
f"# 不适用条件:与「{err[:30]}」不同的错误\n\n"
|
|
1542
1685
|
f"错误:{err}\n修复:{fix}\n")
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1686
|
+
if as_proposals:
|
|
1687
|
+
# 自动管线:入审核队列(判据指纹随提案落盘,复核者不能放宽;
|
|
1688
|
+
# payload_hash 幂等——同内容重试返回原 pid)
|
|
1689
|
+
pid = self.propose(
|
|
1690
|
+
kid, content, layer="knowledge", tags=["fix_pair"],
|
|
1691
|
+
verify={"kind": "data",
|
|
1692
|
+
"assertions": ["error/fix 均非空且来自真实行为日志",
|
|
1693
|
+
"与既有 fix_pair 知识不重复"]})
|
|
1694
|
+
pids.append(pid)
|
|
1695
|
+
else:
|
|
1696
|
+
self.add(kid, content, layer="knowledge", tags=["fix_pair"],
|
|
1697
|
+
verification_basis="data", importance=0.7)
|
|
1698
|
+
kno_ids.append(kid)
|
|
1546
1699
|
# 2) 负记忆:这个错误不是死路(防止重复深挖)
|
|
1547
1700
|
rid = self.add_rejected(
|
|
1548
1701
|
hypothesis=f"「{err[:60]}」需要深挖根因(无现成解法)",
|
|
1549
1702
|
reason=f"已有修复:{fix[:80]}",
|
|
1550
1703
|
verification_basis="data", tags=["fix_pair"])
|
|
1551
1704
|
rej_ids.append(rid)
|
|
1552
|
-
|
|
1553
|
-
|
|
1705
|
+
result = {"pairs": [{"error": e, "fix": f} for e, f in uniq],
|
|
1706
|
+
"rejected_ids": rej_ids, "knowledge_ids": kno_ids}
|
|
1707
|
+
if as_proposals:
|
|
1708
|
+
result["as_proposals"] = True
|
|
1709
|
+
result["pids"] = pids
|
|
1710
|
+
return result
|
|
1554
1711
|
|
|
1555
1712
|
# ================= 4. 审核队列(inbox → decisions) =================
|
|
1556
1713
|
|
|
@@ -1575,17 +1732,18 @@ class MdCGOS(MdCG):
|
|
|
1575
1732
|
"""
|
|
1576
1733
|
phash = _sig(content)
|
|
1577
1734
|
with FileLock(self.inbox_log, strict=True):
|
|
1735
|
+
# 增量对账(issue #32):原实现每条全量 read_jsonl(inbox) +
|
|
1736
|
+
# read_jsonl(decisions)(锁内 O(M+D)/条、批量 O(M²),旧格式行
|
|
1737
|
+
# 逐条重算 sha1);改走 stat 尾部增量索引——文件序与覆盖语义
|
|
1738
|
+
# 与原全量扫描逐位一致(同 phash 按文件序取,已裁决优先 break)。
|
|
1739
|
+
ph_idx = self._inbox_phash_index()
|
|
1578
1740
|
st = self._pid_status()
|
|
1579
1741
|
dup = None
|
|
1580
|
-
for
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
if rh != phash:
|
|
1584
|
-
continue
|
|
1585
|
-
s = st.get(r.get("pid")) or {}
|
|
1586
|
-
dup = {"pid": r.get("pid"),
|
|
1742
|
+
for pid, nid in ph_idx.get(phash, ()):
|
|
1743
|
+
s = st.get(pid) or {}
|
|
1744
|
+
dup = {"pid": pid,
|
|
1587
1745
|
"status": s.get("status") or "pending",
|
|
1588
|
-
"node_id":
|
|
1746
|
+
"node_id": nid}
|
|
1589
1747
|
if dup["status"] in ("accepted", "rejected"):
|
|
1590
1748
|
break # 已裁决的最有信息量,优先返回
|
|
1591
1749
|
if dup:
|
|
@@ -1619,14 +1777,135 @@ class MdCGOS(MdCG):
|
|
|
1619
1777
|
"dup_of": None, "dup_status": None}
|
|
1620
1778
|
return pid
|
|
1621
1779
|
|
|
1622
|
-
#
|
|
1780
|
+
# 生效条件:stat decisions_log 失败(OSError)时把 _pid_st 置空 dict、两扫描键置 -1 并返回空 dict;size 与 mtime_ns 均与缓存键一致时直接返回 _pid_st(零解析);缓存键为 -1(首装)或当前 size 小于已扫描偏移(外部非合作重写/回退)时经 read_jsonl_tail(path, 0) 全量重建 _pid_st,否则经 read_jsonl_tail 从已扫描偏移起增量并入,逐条把 r.get("pid") 为真值的记录写入 _pid_st(后并入覆盖先并入);水位存 read_jsonl_tail 返回的真实 EOF 偏移(end 为 None 时回落 stat size),mtime_ns 存读前 stat 值,返回 _pid_st。
|
|
1623
1781
|
def _pid_status(self):
|
|
1624
|
-
"""pid → 最新一条裁决记录(多轮再审批时取最后一轮)。
|
|
1625
|
-
|
|
1626
|
-
|
|
1782
|
+
"""pid → 最新一条裁决记录(多轮再审批时取最后一轮)。
|
|
1783
|
+
|
|
1784
|
+
增量缓存(issue #32):原实现每调用全量 read_jsonl(decisions_log)
|
|
1785
|
+
(json.loads 逐条),propose 对账每条 O(D)、批量 O(M×D)。append-only
|
|
1786
|
+
契约下改为 stat 尾部对账:size/mtime 未变零解析;size 增长只解析
|
|
1787
|
+
新增字节;size 回退/首装全量重建兜底。mtime 单变 size 不变(touch
|
|
1788
|
+
类)走增量窗口=0 行,结果不变。跨进程 append 由 stat 自动并入。
|
|
1789
|
+
水位口径(竞态修复):存 read_jsonl_tail 返回的**真实 EOF 偏移**,
|
|
1790
|
+
不存读前 stat 的 size——stat→read 窗口内的并发 append 本轮已并入,
|
|
1791
|
+
水位偏小会让下一轮重读同一段(本缓存是 dict 后写覆盖不受损,但与
|
|
1792
|
+
列表型缓存共用同一口径)。
|
|
1793
|
+
边界(与检索读缓存同款诚实声明):外部**非 append 形态**重写文件
|
|
1794
|
+
(同 size 改内容)不在合作写者协议内,不保证可见。
|
|
1795
|
+
"""
|
|
1796
|
+
try:
|
|
1797
|
+
sti = os.stat(self.decisions_log)
|
|
1798
|
+
size, mtime = sti.st_size, sti.st_mtime_ns
|
|
1799
|
+
except OSError:
|
|
1800
|
+
self._pid_st, self._pid_st_size, self._pid_st_mtime = {}, -1, -1
|
|
1801
|
+
return self._pid_st
|
|
1802
|
+
if size == self._pid_st_size and mtime == self._pid_st_mtime:
|
|
1803
|
+
return self._pid_st # 无新内容(零解析)
|
|
1804
|
+
full = self._pid_st_size < 0 or size < self._pid_st_size
|
|
1805
|
+
if full:
|
|
1806
|
+
self._pid_st = {}
|
|
1807
|
+
src, end = read_jsonl_tail(self.decisions_log,
|
|
1808
|
+
0 if full else self._pid_st_size)
|
|
1809
|
+
for r in src:
|
|
1627
1810
|
if r.get("pid"):
|
|
1628
|
-
|
|
1629
|
-
|
|
1811
|
+
self._pid_st[r["pid"]] = r
|
|
1812
|
+
self._pid_st_size = size if end is None else end
|
|
1813
|
+
self._pid_st_mtime = mtime
|
|
1814
|
+
return self._pid_st
|
|
1815
|
+
|
|
1816
|
+
# 生效条件:stat inbox_log 失败(OSError)时把 _inbox_idx 置空 dict、两扫描键置 -1 并返回空 dict;size 与 mtime_ns 均与缓存键一致时直接返回 _inbox_idx(零解析);缓存键为 -1(首装)或当前 size 小于已扫描偏移时经 read_jsonl_tail(path, 0) 全量重建,否则经 read_jsonl_tail 增量并入,逐条以 r.get("payload_hash") 或(缺键时)_sig(r.get("content") or "") 为 ph 把 (r.get("pid"), r.get("id")) 追加进 _inbox_idx[ph](文件序);水位存 read_jsonl_tail 返回的真实 EOF 偏移(end 为 None 时回落 stat size),mtime_ns 存读前 stat 值,返回 _inbox_idx。
|
|
1817
|
+
def _inbox_phash_index(self):
|
|
1818
|
+
"""inbox 的 phash → [(pid, node_id)](文件序)增量索引(propose 对账用)。
|
|
1819
|
+
|
|
1820
|
+
与 _pid_status 同款 stat 尾部对账(issue #32)。存量旧格式行
|
|
1821
|
+
(无 payload_hash)在**并入时**现算一次 _sig(此后常驻,不再
|
|
1822
|
+
每条 propose 重算——旧路径每条重算 M 次 sha1)。
|
|
1823
|
+
水位口径(竞态修复,同 _pid_status):存真实 EOF 偏移,不存读前
|
|
1824
|
+
stat 的 size——窗口内并发 append 不得在下轮重复并入。
|
|
1825
|
+
"""
|
|
1826
|
+
try:
|
|
1827
|
+
sti = os.stat(self.inbox_log)
|
|
1828
|
+
size, mtime = sti.st_size, sti.st_mtime_ns
|
|
1829
|
+
except OSError:
|
|
1830
|
+
self._inbox_idx, self._inbox_idx_size, self._inbox_idx_mtime = \
|
|
1831
|
+
{}, -1, -1
|
|
1832
|
+
return self._inbox_idx
|
|
1833
|
+
if size == self._inbox_idx_size and mtime == self._inbox_idx_mtime:
|
|
1834
|
+
return self._inbox_idx # 无新内容(零解析)
|
|
1835
|
+
full = self._inbox_idx_size < 0 or size < self._inbox_idx_size
|
|
1836
|
+
if full:
|
|
1837
|
+
self._inbox_idx = {}
|
|
1838
|
+
src, end = read_jsonl_tail(self.inbox_log,
|
|
1839
|
+
0 if full else self._inbox_idx_size)
|
|
1840
|
+
for r in src:
|
|
1841
|
+
ph = r.get("payload_hash") or _sig(r.get("content") or "")
|
|
1842
|
+
self._inbox_idx.setdefault(ph, []).append(
|
|
1843
|
+
(r.get("pid"), r.get("id")))
|
|
1844
|
+
self._inbox_idx_size = size if end is None else end
|
|
1845
|
+
self._inbox_idx_mtime = mtime
|
|
1846
|
+
return self._inbox_idx
|
|
1847
|
+
|
|
1848
|
+
# 生效条件:stat inbox_log 失败(OSError)时把 _inbox_recs 置空列表、两扫描键置 -1 并返回它;size 与 mtime_ns 均与缓存键一致时直接返回 _inbox_recs(零解析);缓存键为 -1(首装)或当前 size 小于已扫描偏移时以 read_jsonl_tail(path, 0) 全量重建,否则以 read_jsonl_tail(offset) 结果 extend 增量并入;水位存 read_jsonl_tail 返回的真实 EOF 偏移(end 为 None 时回落 stat size),mtime_ns 存读前 stat 值,返回 _inbox_recs(内部缓存,调用方只读不得变更)。
|
|
1849
|
+
def _inbox_records(self):
|
|
1850
|
+
"""inbox 全记录(文件序)增量缓存——review 治理面单次调用共用一次解析。
|
|
1851
|
+
|
|
1852
|
+
与 _pid_status 同款 stat 尾部对账(issue #35):原 review_decide 线性
|
|
1853
|
+
扫 inbox 找 pid、_cascade_dedup 再全量读一遍(2 遍/调用);改走本
|
|
1854
|
+
缓存后稳态零解析,调用方在内存列表上线性扫(万条 ~1ms 级,无 IO)。
|
|
1855
|
+
水位口径(竞态修复):存 read_jsonl_tail 返回的**真实 EOF 偏移**,
|
|
1856
|
+
不存读前 stat 的 size——stat→read 窗口内的并发 append 本轮已并入,
|
|
1857
|
+
水位偏小会让下一轮 extend 重读同一条(review_list 重复 pid、
|
|
1858
|
+
_cascade_dedup 连写两条 reject),且稳态 size 只增、永不自愈。
|
|
1859
|
+
"""
|
|
1860
|
+
try:
|
|
1861
|
+
sti = os.stat(self.inbox_log)
|
|
1862
|
+
size, mtime = sti.st_size, sti.st_mtime_ns
|
|
1863
|
+
except OSError:
|
|
1864
|
+
self._inbox_recs, self._inbox_recs_size, self._inbox_recs_mtime = \
|
|
1865
|
+
[], -1, -1
|
|
1866
|
+
return self._inbox_recs
|
|
1867
|
+
if size == self._inbox_recs_size and mtime == self._inbox_recs_mtime:
|
|
1868
|
+
return self._inbox_recs # 无新内容(零解析)
|
|
1869
|
+
full = self._inbox_recs_size < 0 or size < self._inbox_recs_size
|
|
1870
|
+
if full:
|
|
1871
|
+
self._inbox_recs = []
|
|
1872
|
+
src, end = read_jsonl_tail(self.inbox_log,
|
|
1873
|
+
0 if full else self._inbox_recs_size)
|
|
1874
|
+
self._inbox_recs.extend(src)
|
|
1875
|
+
self._inbox_recs_size = size if end is None else end
|
|
1876
|
+
self._inbox_recs_mtime = mtime
|
|
1877
|
+
return self._inbox_recs
|
|
1878
|
+
|
|
1879
|
+
# 生效条件:stat decisions_log 失败(OSError)时把 _dec_recs 置空列表、两扫描键置 -1 并返回它;size 与 mtime_ns 均与缓存键一致时直接返回 _dec_recs(零解析);缓存键为 -1(首装)或当前 size 小于已扫描偏移时以 read_jsonl_tail(path, 0) 全量重建,否则以 read_jsonl_tail(offset) 结果 extend 增量并入;水位存 read_jsonl_tail 返回的真实 EOF 偏移(end 为 None 时回落 stat size),mtime_ns 存读前 stat 值,返回 _dec_recs(内部缓存,调用方只读不得变更)。
|
|
1880
|
+
def _decisions_records(self):
|
|
1881
|
+
"""decisions 全记录(文件序)增量缓存——review 治理面单次调用共用一次解析。
|
|
1882
|
+
|
|
1883
|
+
issue #35:原 review_stats 全量读 decisions 统计、verify_review_record
|
|
1884
|
+
全量线性扫找单条 pid(每调用 1 遍整文件 json.loads);改走本缓存后
|
|
1885
|
+
稳态零解析,调用方内存线性扫。与 _pid_status(pid→最新)互补:
|
|
1886
|
+
本缓存保全量记录(多轮裁决历史、by_decision 统计口径)。
|
|
1887
|
+
水位口径(竞态修复,同 _inbox_records):存真实 EOF 偏移——窗口内
|
|
1888
|
+
并发 append 不得在下一轮重复 extend(review_stats 计数虚高/翻倍、
|
|
1889
|
+
永不自愈)。
|
|
1890
|
+
"""
|
|
1891
|
+
try:
|
|
1892
|
+
sti = os.stat(self.decisions_log)
|
|
1893
|
+
size, mtime = sti.st_size, sti.st_mtime_ns
|
|
1894
|
+
except OSError:
|
|
1895
|
+
self._dec_recs, self._dec_recs_size, self._dec_recs_mtime = \
|
|
1896
|
+
[], -1, -1
|
|
1897
|
+
return self._dec_recs
|
|
1898
|
+
if size == self._dec_recs_size and mtime == self._dec_recs_mtime:
|
|
1899
|
+
return self._dec_recs # 无新内容(零解析)
|
|
1900
|
+
full = self._dec_recs_size < 0 or size < self._dec_recs_size
|
|
1901
|
+
if full:
|
|
1902
|
+
self._dec_recs = []
|
|
1903
|
+
src, end = read_jsonl_tail(self.decisions_log,
|
|
1904
|
+
0 if full else self._dec_recs_size)
|
|
1905
|
+
self._dec_recs.extend(src)
|
|
1906
|
+
self._dec_recs_size = size if end is None else end
|
|
1907
|
+
self._dec_recs_mtime = mtime
|
|
1908
|
+
return self._dec_recs
|
|
1630
1909
|
|
|
1631
1910
|
# 生效条件:实例已构建(内部先读 _pid_status());返回其 status ∈ TERMINAL_DECISION_STATUS(accepted/rejected/noop)的 pid 集合,status=="needs_reapproval" 视为未关闭、不计入;
|
|
1632
1911
|
def _closed_pids(self):
|
|
@@ -1639,7 +1918,9 @@ class MdCGOS(MdCG):
|
|
|
1639
1918
|
"""待审核候选(含被红队打回、待再审批的条目)。"""
|
|
1640
1919
|
st = self._pid_status()
|
|
1641
1920
|
out = []
|
|
1642
|
-
|
|
1921
|
+
# issue #35:走全记录增量缓存(稳态零解析)——review_stats 链路单次
|
|
1922
|
+
# 调用共用一次解析;rec=dict(r) 复制,不改内部缓存。
|
|
1923
|
+
for r in self._inbox_records():
|
|
1643
1924
|
s = st.get(r.get("pid")) or {}
|
|
1644
1925
|
if s.get("status") in TERMINAL_DECISION_STATUS:
|
|
1645
1926
|
continue
|
|
@@ -1660,7 +1941,9 @@ class MdCGOS(MdCG):
|
|
|
1660
1941
|
视图复用 review_list/_closed_pids,避免在此复制第二份终态判定逻辑。
|
|
1661
1942
|
"""
|
|
1662
1943
|
by = {}
|
|
1663
|
-
|
|
1944
|
+
# issue #35:走全记录增量缓存(稳态零解析)——原每次全量逐行
|
|
1945
|
+
# json.loads,与 review_list/_closed_pids 链路重复解析同一文件。
|
|
1946
|
+
for r in self._decisions_records():
|
|
1664
1947
|
d = str(r.get("decision") or "").strip() or "unknown"
|
|
1665
1948
|
by[d] = by.get(d, 0) + 1
|
|
1666
1949
|
return {"records": sum(by.values()), "by_decision": by,
|
|
@@ -1789,7 +2072,9 @@ class MdCGOS(MdCG):
|
|
|
1789
2072
|
closed = []
|
|
1790
2073
|
with FileLock(self.decisions_log, strict=True):
|
|
1791
2074
|
st = self._pid_status()
|
|
1792
|
-
|
|
2075
|
+
# issue #35:走全记录增量缓存(稳态零解析)——原与 review_decide
|
|
2076
|
+
# 开头的找 pid 扫描重复全量读同一 inbox(2 遍/调用)。
|
|
2077
|
+
for r in self._inbox_records():
|
|
1793
2078
|
bpid = r.get("pid")
|
|
1794
2079
|
if not bpid or bpid == pid or bpid in st:
|
|
1795
2080
|
continue # 自己 / 已有裁决记录(含 needs_reapproval)跳过
|
|
@@ -1840,7 +2125,9 @@ class MdCGOS(MdCG):
|
|
|
1840
2125
|
return {"ok": False, "error": "node_not_found"}
|
|
1841
2126
|
fm = node.get("frontmatter") or {}
|
|
1842
2127
|
pid, rnd = fm.get("pid"), fm.get("round")
|
|
1843
|
-
|
|
2128
|
+
# issue #35:走全记录增量缓存后内存线性扫(稳态零解析)——原每次
|
|
2129
|
+
# 全量逐行 json.loads 整份 decisions 只为找一条 pid+round。
|
|
2130
|
+
src = next((r for r in self._decisions_records()
|
|
1844
2131
|
if r.get("pid") == pid
|
|
1845
2132
|
and int(r.get("round") or 0) == int(rnd or 0)), None)
|
|
1846
2133
|
if not src:
|
|
@@ -1855,10 +2142,11 @@ class MdCGOS(MdCG):
|
|
|
1855
2142
|
"verify_hash": src.get("verify_hash"),
|
|
1856
2143
|
"source": "hippocampus/decisions.jsonl"}
|
|
1857
2144
|
|
|
1858
|
-
# 生效条件:decision 须为 DECISION_ACTIONS("accept"/"reject"/"edit"/"merge"/"noop")之一(否则 raise ValueError),inbox_log 中须有 pid 匹配记录(否则 {'ok': False, 'error': 'pid_not_found'}),且 pid 不在 self._closed_pids() 中(否则 'already_decided');edits 为真值且含 "verify"、或 redteam 为真值且含 "verify" 时返回 'verify_readonly';last_status=="needs_reapproval" 时须 redteam.verdict 归一化为 "pass" 且 round_no>last_round(否则 'reapproval_required' / 'round_not_advanced');rt_v=="reject" 或(decision=="reject" 且 rt_issues 非空)时记 needs_reapproval 不落节点;decision=="accept" 且 rt_v 为空且 _redteam_required() 为真时返回 'redteam_required';其余 accept/edit 按 item(edit 时用 edits.get 覆盖 content/tags/layer)add+flush 落节点,merge 须 merge_into 或 item.extra.merge_into 指向的节点存在(否则 'merge_target_not_found'
|
|
2145
|
+
# 生效条件:decision 须为 DECISION_ACTIONS("accept"/"reject"/"edit"/"merge"/"noop")之一(否则 raise ValueError),inbox_log 中须有 pid 匹配记录(否则 {'ok': False, 'error': 'pid_not_found'}),且 pid 不在 self._closed_pids() 中(否则 'already_decided');edits 为真值且含 "verify"、或 redteam 为真值且含 "verify" 时返回 'verify_readonly';last_status=="needs_reapproval" 时须 redteam.verdict 归一化为 "pass" 且 round_no>last_round(否则 'reapproval_required' / 'round_not_advanced');rt_v=="reject" 或(decision=="reject" 且 rt_issues 非空)时记 needs_reapproval 不落节点;decision=="accept" 且 rt_v 为空且 _redteam_required() 为真时返回 'redteam_required';其余 accept/edit 按 item(edit 时用 edits.get 覆盖 content/tags/layer)add+flush 落节点,merge 须 merge_into 或 item.extra.merge_into 指向的节点存在(否则 'merge_target_not_found'),且写入前经与 add 同款双闸(N131,2026-09-25:principal 在位先 require_layer_write(目标层, 目标敏感度)——与 MdCGSecure.add 同序同错型;再 protect.guard_write(override=override)——self/anchor 层、immutable 标记,拒绝抛 ProtectionError/AccessDenied 且提案留 pending 不落库)后追加内容并定向索引 upsert(_node_entry 同源条目写入 index/_dirty)+flush,reject 与 noop 只记裁决(status 分别为 "rejected"/"noop");最后统一 _record_decision + _cascade_dedup + flush 后返回 result。
|
|
1859
2146
|
def review_decide(self, pid: str, decision: str, edits: dict = None,
|
|
1860
2147
|
merge_into: str = None, reason: str = "",
|
|
1861
|
-
redteam: dict = None, issues=None
|
|
2148
|
+
redteam: dict = None, issues=None,
|
|
2149
|
+
override: bool = False):
|
|
1862
2150
|
"""审核裁决:accept / reject / edit / merge / noop。
|
|
1863
2151
|
|
|
1864
2152
|
accept → 按 inbox 原样写入
|
|
@@ -1880,7 +2168,9 @@ class MdCGOS(MdCG):
|
|
|
1880
2168
|
"""
|
|
1881
2169
|
if decision not in DECISION_ACTIONS:
|
|
1882
2170
|
raise ValueError(f"未知裁决:{decision}")
|
|
1883
|
-
|
|
2171
|
+
# issue #35:走全记录增量缓存后内存线性扫(稳态零解析)——原每次
|
|
2172
|
+
# 全量逐行 json.loads 整份 inbox 只为找一条 pid。
|
|
2173
|
+
item = next((r for r in self._inbox_records()
|
|
1884
2174
|
if r.get("pid") == pid), None)
|
|
1885
2175
|
if not item:
|
|
1886
2176
|
return {"ok": False, "error": "pid_not_found"}
|
|
@@ -1953,7 +2243,8 @@ class MdCGOS(MdCG):
|
|
|
1953
2243
|
# 未达 autoflush(64) 阈值时进程退出即永久丢失——裁决进程(review_cli /
|
|
1954
2244
|
# MCP op=review)通常只写 1~2 条,不 flush 则「节点在盘上但索引无条目」,
|
|
1955
2245
|
# 其他进程与重载后的长驻进程都检索不到,只能靠某次全量 rebuild 偶然救回。
|
|
1956
|
-
# merge
|
|
2246
|
+
# merge 分支同样直写节点文件,其收尾已改为同款定向 upsert+flush
|
|
2247
|
+
# (issue #34,见 else 分支注释)。
|
|
1957
2248
|
self.flush()
|
|
1958
2249
|
result.update(ok=True, node_id=nid)
|
|
1959
2250
|
else: # merge
|
|
@@ -1961,6 +2252,22 @@ class MdCGOS(MdCG):
|
|
|
1961
2252
|
tgt = self.get(target) if target else None
|
|
1962
2253
|
if not tgt:
|
|
1963
2254
|
return {"ok": False, "error": "merge_target_not_found"}
|
|
2255
|
+
# 写保护(N131,2026-09-25):merge = 对目标节点的一次**覆写**
|
|
2256
|
+
# (_write_node 追加正文),与 accept/edit 的 add 落点同受写保护——
|
|
2257
|
+
# 此前直写绕过双闸,orchestr forbidden「anchor/self/goals/knowledge
|
|
2258
|
+
# 层」被打穿。与 add 同序同错型:principal 层写闸在先(对照
|
|
2259
|
+
# MdCGSecure.add),引擎级 guard_write 在后(对照基类 add :1311);
|
|
2260
|
+
# 闸必须在 _record_decision 之前抛出——审计节点写入本就在其
|
|
2261
|
+
# try/except 内,闸放那里会被吞成 record_error 形同虚设。
|
|
2262
|
+
_p = getattr(self, "principal", None)
|
|
2263
|
+
if _p is not None and hasattr(_p, "require_layer_write"):
|
|
2264
|
+
_e = (self.index.get("nodes") or {}).get(target) or {}
|
|
2265
|
+
_p.require_layer_write(
|
|
2266
|
+
_e.get("layer") or tgt["frontmatter"].get("layer")
|
|
2267
|
+
or tgt["path"].split("/")[0],
|
|
2268
|
+
_e.get("sensitivity") or DEFAULT_SENSITIVITY)
|
|
2269
|
+
protect.guard_write(self, target, override=override,
|
|
2270
|
+
actor=getattr(self, "actor", None))
|
|
1964
2271
|
fm = dict(tgt["frontmatter"])
|
|
1965
2272
|
merged_content = (tgt["content"].rstrip() + "\n\n" +
|
|
1966
2273
|
item["content"].strip() + "\n")
|
|
@@ -1972,7 +2279,24 @@ class MdCGOS(MdCG):
|
|
|
1972
2279
|
fm["non_applicable_conditions"] = neg
|
|
1973
2280
|
self._write_node(target, os.path.join(self.root, tgt["path"]),
|
|
1974
2281
|
fm, merged_content)
|
|
1975
|
-
|
|
2282
|
+
# 定向索引 upsert(issue #34):merge 只改一个目标节点,原
|
|
2283
|
+
# rebuild_index 收尾是 _scan_nodes 全库 O(N) 逐文件扫描
|
|
2284
|
+
# (1500 池实测 ~97-247ms/次),与 accept/edit 的 add+flush
|
|
2285
|
+
# O(1) 增量收尾不对称。改为:单文件条目重算(_node_entry 与
|
|
2286
|
+
# _scan_nodes 同源唯一真源——字段集零漂移)+ 内存索引/增量
|
|
2287
|
+
# 日志定向写入 + flush。不走 _stage:目标已在索引,_stage 会
|
|
2288
|
+
# 虚增 bucket 计数;merge 不改 tags/目录,bucket 不变。
|
|
2289
|
+
# _dirty 置数同时推进 readcache 代际(写盘后同实例不陈旧)。
|
|
2290
|
+
try:
|
|
2291
|
+
tp = os.path.join(self.root, tgt["path"])
|
|
2292
|
+
with open(tp, encoding="utf-8") as f:
|
|
2293
|
+
fm2, c2 = nodefile.loads(f.read())
|
|
2294
|
+
e2 = self._node_entry(tp, tgt["path"].split("/")[0], fm2, c2)
|
|
2295
|
+
self.index["nodes"][target] = e2
|
|
2296
|
+
self._dirty[target] = e2
|
|
2297
|
+
except OSError:
|
|
2298
|
+
pass # 单文件重读失败(极罕见):条目留旧值,下次 rebuild 对账
|
|
2299
|
+
self.flush()
|
|
1976
2300
|
result.update(ok=True, node_id=target)
|
|
1977
2301
|
|
|
1978
2302
|
# status 映射统一出口:reject→"rejected"、noop→"noop"(同为终态,见
|
|
@@ -2018,7 +2342,7 @@ class MdCGOS(MdCG):
|
|
|
2018
2342
|
h = _sig(content or "", 16)
|
|
2019
2343
|
dst = os.path.join(self.trash_dir, f"{node_id}.md")
|
|
2020
2344
|
try:
|
|
2021
|
-
|
|
2345
|
+
publish(src, dst)
|
|
2022
2346
|
except OSError as exc:
|
|
2023
2347
|
return {"ok": False, "error": str(exc)}
|
|
2024
2348
|
append_jsonl(self.deletions_log, {"t": time.time(), "id": node_id,
|
|
@@ -2042,7 +2366,7 @@ class MdCGOS(MdCG):
|
|
|
2042
2366
|
def is_tombstoned(self, node_id: str):
|
|
2043
2367
|
return any(r.get("id") == node_id for r in read_jsonl(self.deletions_log))
|
|
2044
2368
|
|
|
2045
|
-
# 生效条件:当 node_id 传入时,若 deletions_log 中存在该 id 且 force=False 返回 tombstoned 拒绝;否则检查 trash_dir/{node_id}.md,os.path.exists 为 False 返回 not_in_trash
|
|
2369
|
+
# 生效条件:当 node_id 传入时,若 deletions_log 中存在该 id 且 force=False 返回 tombstoned 拒绝;否则检查 trash_dir/{node_id}.md,os.path.exists 为 False 返回 not_in_trash;可打开则读取并以 add(override=True) + trash frontmatter 元数据全量透传(显式形参逐项传,其余键经 **extra 回写;lifecycle_state 仅在 active→该态合法迁移时透传)恢复、移除 trash 源、audit,返回 ok True/id/forced=bool(force);
|
|
2046
2370
|
def restore(self, node_id: str, force: bool = False):
|
|
2047
2371
|
"""恢复:若在删除清单中且未 force → 拒绝(恢复时删除检查)。"""
|
|
2048
2372
|
tomb = [r for r in read_jsonl(self.deletions_log) if r.get("id") == node_id]
|
|
@@ -2055,13 +2379,52 @@ class MdCGOS(MdCG):
|
|
|
2055
2379
|
with open(src, encoding="utf-8") as f:
|
|
2056
2380
|
fm, content = nodefile.loads(f.read())
|
|
2057
2381
|
layer = fm.get("layer", "knowledge")
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2382
|
+
# 恢复 = 原样放回:add 是**全量重建 fm**,只传个位数字段会把 edges/
|
|
2383
|
+
# depends_on/验证态/生命周期/created_at/语义摘要/证据计数等元数据永久
|
|
2384
|
+
# 抹掉(下方 os.remove 删 trash 源后不可再恢复)。故 add 显式形参对应
|
|
2385
|
+
# 的键逐项透传;其余键(created_at/evidence_*/protected/temporal/
|
|
2386
|
+
# derived_relation…)经 **extra 回写(fm.update 通道覆盖默认值)。
|
|
2387
|
+
# _skip 必须覆盖 add 全部显式形参名——**extra 撞形参名直接 TypeError。
|
|
2388
|
+
_skip = ("id", "layer", "tags", "condition_space", "importance",
|
|
2389
|
+
"confidence", "verification_basis", "edges",
|
|
2390
|
+
"non_applicable_conditions", "derived_from", "relation",
|
|
2391
|
+
"semantic", "depends_on", "valid_from", "valid_until",
|
|
2392
|
+
"effective_from", "effective_until", "believed_at",
|
|
2393
|
+
"verification_state", "override", "consistency",
|
|
2394
|
+
"on_conflict", "state", "sensitivity", "derived_relation",
|
|
2395
|
+
"content", "node_id")
|
|
2396
|
+
_extra = {k: v for k, v in fm.items()
|
|
2397
|
+
if k not in _skip and v not in (None, "", [], {})}
|
|
2398
|
+
# 生命周期状态走迁移裁决:restore 时节点已摘索引、按新节点(active)
|
|
2399
|
+
# 起判,active→archived 跳级会被拒——不可迁移时不透传(落 active),
|
|
2400
|
+
# 不让罕见 corner case 阻断恢复主流程。
|
|
2401
|
+
from . import lifecycle as _lc
|
|
2402
|
+
from . import provenance as _prov
|
|
2403
|
+
_ls = fm.get(_lc.STATE_FIELD)
|
|
2404
|
+
if _ls and _lc.can_transition("active", _ls):
|
|
2405
|
+
_extra[_lc.STATE_FIELD] = _ls
|
|
2406
|
+
# 验证态同样按新节点(unverified)起判:非法值透传会被 require_transition
|
|
2407
|
+
# 直接拒掉,过滤为 None(落 unverified)保证恢复不被脏数据卡死。
|
|
2408
|
+
_vs = fm.get("verification_state")
|
|
2409
|
+
self.add(node_id, content, layer=layer, tags=fm.get("tags") or [],
|
|
2410
|
+
override=True, sensitivity=fm.get("sensitivity"),
|
|
2061
2411
|
condition_space=fm.get("condition_space"),
|
|
2062
2412
|
importance=fm.get("importance", 0.5),
|
|
2063
2413
|
confidence=fm.get("confidence", 0.6),
|
|
2064
|
-
verification_basis=fm.get("verification_basis")
|
|
2414
|
+
verification_basis=fm.get("verification_basis"),
|
|
2415
|
+
edges=fm.get("edges"),
|
|
2416
|
+
non_applicable_conditions=fm.get("non_applicable_conditions"),
|
|
2417
|
+
semantic=fm.get("semantic"),
|
|
2418
|
+
depends_on=fm.get("depends_on"),
|
|
2419
|
+
valid_from=fm.get("valid_from"),
|
|
2420
|
+
valid_until=fm.get("valid_until"),
|
|
2421
|
+
effective_from=fm.get("effective_from"),
|
|
2422
|
+
effective_until=fm.get("effective_until"),
|
|
2423
|
+
believed_at=fm.get("believed_at"),
|
|
2424
|
+
verification_state=(_vs if _vs in trust.STATES else None),
|
|
2425
|
+
derived_from=fm.get("derived_from"),
|
|
2426
|
+
relation=fm.get("derived_relation") or _prov.DEFAULT_RELATION,
|
|
2427
|
+
**_extra)
|
|
2065
2428
|
os.remove(src)
|
|
2066
2429
|
self._audit("restore", node_id, forced=bool(force))
|
|
2067
2430
|
return {"ok": True, "id": node_id, "forced": bool(force)}
|
|
@@ -3473,10 +3836,10 @@ class MdCGSecure(MdCGOS):
|
|
|
3473
3836
|
self._index_sensitivity(nid, sens)
|
|
3474
3837
|
return nid
|
|
3475
3838
|
|
|
3476
|
-
# 生效条件:sens 取 sensitivity or DEFAULT_SENSITIVITY,先 principal.require_layer_write(kw.get("layer") or "contextual"
|
|
3839
|
+
# 生效条件:sens 取 sensitivity or DEFAULT_SENSITIVITY,先 principal.require_layer_write(kw.get("layer", "knowledge"), sens)(缺省与基类 MdCGOS.propose 的 layer="knowledge" 一致——此前误用 or "contextual" 导致校验层与落盘层错位:knowledge-only 身份被误拒 / contextual-only 身份入队成死提案,2026-09-25 缺陷 #5),再转 super().propose(node_id, content, sensitivity=sens) 并返回其结果。
|
|
3477
3840
|
def propose(self, node_id: str, content: str, sensitivity: str = None, **kw):
|
|
3478
3841
|
sens = sensitivity or DEFAULT_SENSITIVITY
|
|
3479
|
-
self.principal.require_layer_write(kw.get("layer"
|
|
3842
|
+
self.principal.require_layer_write(kw.get("layer", "knowledge"), sens)
|
|
3480
3843
|
return super().propose(node_id, content, sensitivity=sens, **kw)
|
|
3481
3844
|
|
|
3482
3845
|
# 生效条件:sens 取 sensitivity or DEFAULT_SENSITIVITY,先 _rank(sens) 并 principal.require_layer_write("goals", sens),再转 super().add_goal,最后按 gid 调 _index_sensitivity 并返回 gid。
|
|
@@ -3493,6 +3856,16 @@ class MdCGSecure(MdCGOS):
|
|
|
3493
3856
|
self.principal.require_layer_write("goals", DEFAULT_SENSITIVITY)
|
|
3494
3857
|
return super().set_goal_status(node_id, status)
|
|
3495
3858
|
|
|
3859
|
+
# 生效条件:verdict(转 str 去空白 lower)为 "falsified" 且索引中存在 node_id 条目时,先取该条目 layer 与 sensitivity(缺省回落 DEFAULT_SENSITIVITY)调 principal.require_layer_write——falsified 删除 = 对原节点层的一次删除写(N130,2026-09-25:verify 角色 layers_allow 本就只含 rejected/contextual,不得改/删被验证内容所在层,tokens.py verify spec forbidden 显式列明),与 add/add_rejected 同一闸口;随后把 override 原样转 super().verify(受保护节点的 guard_forget 快照留痕在基类 falsified 分支内)。verdict 非 falsified 或索引无此节点时不加闸直接透传(not_found 语义由基类维持)。
|
|
3860
|
+
def verify(self, node_id: str, evidence: str, verdict: str,
|
|
3861
|
+
override: bool = False):
|
|
3862
|
+
if str(verdict or "").strip().lower() == "falsified":
|
|
3863
|
+
e = (self.index.get("nodes") or {}).get(node_id)
|
|
3864
|
+
if e is not None:
|
|
3865
|
+
self.principal.require_layer_write(
|
|
3866
|
+
e.get("layer"), e.get("sensitivity") or DEFAULT_SENSITIVITY)
|
|
3867
|
+
return super().verify(node_id, evidence, verdict, override=override)
|
|
3868
|
+
|
|
3496
3869
|
# 生效条件:sens 取 sensitivity or DEFAULT_SENSITIVITY,经 _rank(sens) 与 principal.require_write(sens) 后把 m 基于 meta 复制并 setdefault tenant/session、harness 与 unit 为真值时补入,再强制 m["sensitivity"]=sens,text 经 _seal_content("_recent", text, sens) 后连 tags=tags 一起转 super().remember_event(window 为 None 时不传该参,否则带上 window)。
|
|
3497
3870
|
def remember_event(self, role: str, text: str, tags=None, meta=None,
|
|
3498
3871
|
window=None, sensitivity: str = None):
|
|
@@ -3515,15 +3888,57 @@ class MdCGSecure(MdCGOS):
|
|
|
3515
3888
|
# ---------- 读:密级过滤 ----------
|
|
3516
3889
|
|
|
3517
3890
|
# 生效条件:e 的 sensitivity 为假值时先 _read 回填为 fm 的 sensitivity or DEFAULT_SENSITIVITY,再以 self.principal.allows(sens) 的布尔结果为准。
|
|
3518
|
-
def _readable(self, e) -> bool:
|
|
3891
|
+
def _readable(self, e, session=None) -> bool:
|
|
3892
|
+
"""读可见性单点判定:clearance × sensitivity(密级)∧ 会话绑定(归属)。
|
|
3893
|
+
|
|
3894
|
+
会话绑定(issue #35 设计定稿 2026-09-23,使用者拍板):
|
|
3895
|
+
· public / internal = 跨会话共享档——任何通过 clearance 的会话可见;
|
|
3896
|
+
· private / secret = 会话绑定档——仅归属会话(frontmatter.session)
|
|
3897
|
+
可见;can_admin(设计者,需整体判断)豁免。
|
|
3898
|
+
· 绑定档无归属(存量节点):fail-closed,仅设计者可见(宁可少读,
|
|
3899
|
+
不可越权——与下方 sensitivity 回填同款纪律)。
|
|
3900
|
+
· 查询侧 session 参数(含 "*")不参与绑定档判定——身份不可自报;
|
|
3901
|
+
共享档本就跨会话可见,故该参数在 Secure 层不再改变任何可见性。
|
|
3902
|
+
"""
|
|
3519
3903
|
sens = e.get("sensitivity")
|
|
3520
3904
|
if not sens:
|
|
3521
|
-
#
|
|
3522
|
-
#
|
|
3905
|
+
# 索引可能被「无密级上下文」的实例重建而丢掉该字段:按盘上真相回填。
|
|
3906
|
+
# V21-2(批次 34,外部报告):`_read` 失败(返回 None 头)时**不得**
|
|
3907
|
+
# 回落宽松默认——那会把受保护节点判成 internal 对平级可见
|
|
3908
|
+
# (fail-open)。密级未知 = 按最高档 secret 处理(fail-closed:
|
|
3909
|
+
# 宁可误禁,不可越权)。
|
|
3523
3910
|
fm, _c = self._read(e)
|
|
3524
|
-
|
|
3911
|
+
if fm is None:
|
|
3912
|
+
sens = "secret"
|
|
3913
|
+
else:
|
|
3914
|
+
sens = fm.get("sensitivity") or DEFAULT_SENSITIVITY
|
|
3525
3915
|
e["sensitivity"] = sens
|
|
3526
|
-
|
|
3916
|
+
# restricted = 错误处置标记(批次 28 分型,使用者裁定):不走纯密级
|
|
3917
|
+
# rank——密级底线 internal ∧ 错误处置链路角色(designer/orchestr/
|
|
3918
|
+
# verify,或 can_admin)。平级(record/worker)与下游(output/guest)
|
|
3919
|
+
# 限读,处置链路必读——故意的冲突设计在此消解。
|
|
3920
|
+
if sens == "restricted":
|
|
3921
|
+
from .security import can_read_restricted
|
|
3922
|
+
return (self.principal.allows("internal")
|
|
3923
|
+
and can_read_restricted(self.principal))
|
|
3924
|
+
if not self.principal.allows(sens):
|
|
3925
|
+
return False
|
|
3926
|
+
if _rank(sens) >= _rank("private"):
|
|
3927
|
+
if self.principal.can_admin:
|
|
3928
|
+
return True
|
|
3929
|
+
# 绑定档判定**恒用 principal.session(服务端身份,不可伪造)**——
|
|
3930
|
+
# 查询侧 session 参数(含 "*")不构成豁免:调用方自报的会话不能
|
|
3931
|
+
# 越过身份看别人的 private(与 _attribution「env 固定会话时请求
|
|
3932
|
+
# 声明一律忽略」同款纪律)。
|
|
3933
|
+
nsess = e.get("session")
|
|
3934
|
+
return bool(nsess) and nsess == self.principal.session
|
|
3935
|
+
return True
|
|
3936
|
+
|
|
3937
|
+
# 生效条件:nid 在 index["nodes"] 中有条目且 _readable(e) 为真时返回 True,否则(无条目/不可见)返回 False;作为 chain.adjacency 的读隔离谓词(cg._chain_visible)被消费——关系链面(causal_chain/explain_chain/causal_path/检索 chain 路 provenance 经 expand_from_seeds)由此单点隔离,不可见节点的出边、边条件文本与下游拓扑不再进入链展开;实例身份稳定(_readable 绑定档恒用 principal.session),与 adjacency 缓存无串台。
|
|
3938
|
+
def _chain_visible(self, nid) -> bool:
|
|
3939
|
+
"""关系链可见性谓词(chain.adjacency 读隔离闸,2026-09-25)。"""
|
|
3940
|
+
e = (self.index.get("nodes") or {}).get(nid)
|
|
3941
|
+
return bool(e) and self._readable(e)
|
|
3527
3942
|
|
|
3528
3943
|
# 生效条件:先以 limit=None 取 super().list_goals(status=status) 的全量,再只保留 index 中 _readable(e) 为真的目标,limit 为真值时返回 keep[:limit]、否则返回全部 keep。
|
|
3529
3944
|
def list_goals(self, status=None, limit=None):
|
|
@@ -3548,6 +3963,13 @@ class MdCGSecure(MdCGOS):
|
|
|
3548
3963
|
continue
|
|
3549
3964
|
if not self.principal.allows(m.get("sensitivity") or DEFAULT_SENSITIVITY):
|
|
3550
3965
|
continue
|
|
3966
|
+
# 会话绑定档(private/secret):近期事件同口径——仅归属会话,
|
|
3967
|
+
# 设计者豁免(issue #35 设计定稿,与 _readable 一致)。
|
|
3968
|
+
msens = m.get("sensitivity") or DEFAULT_SENSITIVITY
|
|
3969
|
+
if (_rank(msens) >= _rank("private")
|
|
3970
|
+
and not self.principal.can_admin
|
|
3971
|
+
and m.get("session") != self.principal.session):
|
|
3972
|
+
continue
|
|
3551
3973
|
if crypto.is_encrypted(r.get("text")):
|
|
3552
3974
|
t = self._open_content("_recent", m, r["text"])
|
|
3553
3975
|
if t is None:
|
|
@@ -3562,18 +3984,18 @@ class MdCGSecure(MdCGOS):
|
|
|
3562
3984
|
self.principal.require_admin("clear_recent")
|
|
3563
3985
|
return super().clear_recent()
|
|
3564
3986
|
|
|
3565
|
-
# 生效条件:在 super()._candidates(layer=layer, roles=roles, include_work=include_work, session=
|
|
3987
|
+
# 生效条件:在 super()._candidates(layer=layer, roles=roles, include_work=include_work, session=None(会话判定上收本层:基类硬等值过滤会误剔共享档的他人节点), branch=branch, ...) 的结果上,只保留 self._readable(e, session=session) 为真的条目(clearance × sensitivity ∧ 会话绑定,见 _readable;时间算子在父类候选层单点已过滤,此处只叠加读可见性)。
|
|
3566
3988
|
def _candidates(self, layer=None, roles=None, include_work=False,
|
|
3567
3989
|
session=None, branch=None, validity=None,
|
|
3568
3990
|
start_time=None, end_time=None, start_operator=None,
|
|
3569
3991
|
end_operator=None, time_axis=None, view=None):
|
|
3570
3992
|
out = super()._candidates(layer=layer, roles=roles, include_work=include_work,
|
|
3571
|
-
session=
|
|
3993
|
+
session=None, branch=branch, validity=validity,
|
|
3572
3994
|
start_time=start_time, end_time=end_time,
|
|
3573
3995
|
start_operator=start_operator,
|
|
3574
3996
|
end_operator=end_operator, time_axis=time_axis,
|
|
3575
3997
|
view=view)
|
|
3576
|
-
return [e for e in out if self._readable(e)]
|
|
3998
|
+
return [e for e in out if self._readable(e, session=session)]
|
|
3577
3999
|
|
|
3578
4000
|
# 生效条件:在 super()._neg_coverage(terms) 的结果上,只保留 self._readable(e) 为真的条目。
|
|
3579
4001
|
def _neg_coverage(self, terms):
|
|
@@ -3603,6 +4025,7 @@ class MdCGSecure(MdCGOS):
|
|
|
3603
4025
|
res, meta = super().search_rrf(*a, **kw)
|
|
3604
4026
|
validity = kw.get("validity")
|
|
3605
4027
|
view = kw.get("view")
|
|
4028
|
+
session = kw.get("session")
|
|
3606
4029
|
now = time.time() if validity else None
|
|
3607
4030
|
_en_t, _ax_t, _why_t = trust.check_time_args(
|
|
3608
4031
|
kw.get("start_time"), kw.get("end_time"), kw.get("start_operator"),
|
|
@@ -3610,8 +4033,11 @@ class MdCGSecure(MdCGOS):
|
|
|
3610
4033
|
keep = []
|
|
3611
4034
|
for r in res:
|
|
3612
4035
|
e = self.index["nodes"].get(r[0]["id"], r[0])
|
|
3613
|
-
if not self._readable(e):
|
|
4036
|
+
if not self._readable(e, session=session):
|
|
3614
4037
|
continue
|
|
4038
|
+
# 会话归属兜底已并入 _readable(session 传参):共享档跨会话可见、
|
|
4039
|
+
# 绑定档(private/secret)按归属会话判定(图扩展绕过 _candidates
|
|
4040
|
+
# 的串台路径由它一并挡住,与 validity/view 同层兜底)。
|
|
3615
4041
|
if view is not None and not roleviews.matches(e, view):
|
|
3616
4042
|
continue
|
|
3617
4043
|
if validity and trust.is_expired(e, now=now):
|
|
@@ -3641,9 +4067,13 @@ class MdCGSecure(MdCGOS):
|
|
|
3641
4067
|
self.principal.require_admin("restore")
|
|
3642
4068
|
return super().restore(node_id, force=force)
|
|
3643
4069
|
|
|
3644
|
-
# 生效条件:先 principal.
|
|
4070
|
+
# 生效条件:先 principal.require_op("review")(语义修正 2026-09-22:裁决权从
|
|
4071
|
+
# require_admin 拆出——编排者/仲裁位持 review op 即可裁决,存在级管理权
|
|
4072
|
+
# (forget/protect/anchor 写)仍由 require_admin 把守、designer 专属;
|
|
4073
|
+
# designer ops=["*"] 天然兼容),再把 *a/**kw 原样转给 super().review_decide;
|
|
4074
|
+
# accept/edit 落节点时的层写仍由下游 require_layer_write 按裁决者可写层拦截。
|
|
3645
4075
|
def review_decide(self, *a, **kw):
|
|
3646
|
-
self.principal.
|
|
4076
|
+
self.principal.require_op("review")
|
|
3647
4077
|
return super().review_decide(*a, **kw)
|
|
3648
4078
|
|
|
3649
4079
|
# 生效条件:先 principal.require_admin("evolution_rollback"),再转 super().evolution_rollback(entry_id, dry_run=dry_run, note=note)。
|