@furongjun1999/dsh-memory 0.4.7 → 0.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -47
- package/codebuddy/CODEBUDDY.md +21 -10
- package/codebuddy/README.md +13 -1
- package/codebuddy/mcp.json +9 -0
- package/docs/GBrain/345/217/257/345/200/237/351/211/264/347/202/271_/347/201/265/346/236/242/350/220/275/347/202/271/344/272/244/346/216/245_20260919.md +169 -0
- package/docs/Pi/345/217/257/345/255/246/344/271/240/344/274/230/347/202/271_/347/201/265/346/236/242/345/244/247/350/204/221/346/224/271/350/277/233/344/272/244/346/216/245_20260915.md +144 -0
- package/docs/README.md +111 -0
- package/docs/discipline/harnesses.yaml +226 -152
- package/docs/discipline/templates/full.md.tmpl +61 -58
- package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_LoCoMo_/347/201/265/346/236/242_.md +127 -0
- package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_LoCoMo_/347/201/265/346/236/242_.png +0 -0
- package/docs/eval//347/254/254/344/270/211/346/226/271/351/252/214/350/257/201/346/212/245/345/221/212_/347/201/265/346/236/242_vs_dejavu_/347/273/237/344/270/200/350/257/204/345/210/206_v7.md +202 -0
- package/docs/experiments/linkref_backfill/candidates_20260917.json +726 -0
- package/docs/experiments/linkref_backfill/candidates_internal_20260917.json +602 -0
- package/docs/experiments/linkref_backfill/candidates_internal_v2.json +603 -0
- package/docs/experiments/linkref_backfill/candidates_secret_20260917.json +884 -0
- package/docs/experiments/linkref_backfill/candidates_secret_v2.json +789 -0
- package/docs/experiments/m4-role-probe/census.py +86 -0
- package/docs/experiments/m4-role-probe/probe.py +89 -0
- package/docs/experiments/mapped_confidence/bench_mapped_conf.py +216 -0
- package/docs/experiments/mapped_confidence/post_check.py +75 -0
- package/docs/experiments/mapped_confidence/repro_thirdparty_tol.py +83 -0
- package/docs/experiments/mapped_confidence/result_mapped_conf.json +215 -0
- package/docs/hive//345/244/232/347/253/257harness/351/200/232/344/277/241/345/245/221/347/272/246_v0.1.md +42 -0
- package/docs/hive//346/243/200/347/264/242/346/224/266/346/225/233/345/256/236/346/265/213/344/270/216S1b/350/256/276/350/256/241_v0.1.md +43 -0
- package/docs/hive//346/243/200/347/264/242/350/267/257/345/276/204/344/270/216/350/256/244/347/237/245/347/273/223/346/236/204/345/245/221/347/272/246_v0.1.md +102 -0
- package/docs/hive//347/234/237/345/256/236/345/272/223/347/253/257/345/210/260/347/253/257/345/256/236/346/265/213_S1b/344/270/216/345/217/254/345/233/236/346/235/203/350/241/241_v0.1.md +57 -0
- package/docs/hive//347/234/237/345/256/236/345/272/223/347/253/257/345/210/260/347/253/257/345/256/236/346/265/213_S7/345/200/222/346/216/222/345/200/231/351/200/211/345/261/202_v0.1.md +126 -0
- package/docs/hive//350/234/202/345/267/242/345/217/214/345/256/236/344/276/213/344/272/222/351/252/214_/350/256/276/350/256/241/345/256/232/347/250/277.md +503 -0
- package/docs/{ → hive/}/350/234/202/345/267/242/345/267/245/344/275/234/350/256/260/345/277/206_/351/241/271/347/233/256/350/256/241/345/210/222.md +14 -2
- package/docs/mdcg/D_meta_/345/267/245/347/250/213/345/214/226/346/226/271/346/241/210_v0.2.md +216 -0
- package/docs/{README → mdcg/README}/350/257/246/347/273/206/347/211/210_v0.4.5.md +631 -625
- package/docs/{ → mdcg/}/344/270/273/344/273/243/347/220/206/345/255/220/344/273/243/347/220/206/350/256/260/345/277/206/346/236/266/346/236/204/350/256/276/350/256/241.md +1 -1
- package/docs/mdcg//344/273/243/347/240/201/350/257/204/345/256/241/344/270/216/346/235/241/344/273/266/345/214/226/346/263/250/351/207/212_/345/245/221/347/272/246_v0.1.md +82 -0
- package/docs/mdcg//345/205/250/345/272/223/344/273/243/347/240/201/350/257/204/345/256/241/344/270/216/346/235/241/344/273/266/345/214/226/346/263/250/351/207/212_/350/256/241/345/210/222_v0.1.md +600 -0
- package/docs/mdcg//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +263 -0
- package/docs/{ → mdcg/}/345/215/225/345/205/203/350/207/252/346/210/221/351/224/232/347/202/271_/347/263/273/347/273/237/346/217/220/347/244/272/350/257/215/346/240/207/345/207/206_v0.3.md +1 -1
- package/docs/mdcg//345/255/220/344/273/243/347/220/206/351/205/215/347/275/256/346/240/207/345/207/206_v0.5.md +236 -0
- package/docs/{ → mdcg/}/346/272/220/347/240/201/347/272/247/346/236/266/346/236/204/345/256/241/350/256/241_GPT/346/211/271/350/257/204/345/257/271/347/205/247_v1.0.md +2 -2
- package/docs/{ → mdcg/}/347/201/265/346/236/242/344/270/211/345/261/202/346/213/206/345/210/206/350/247/204/345/210/222_v0.1.md +181 -181
- package/docs/mdcg//347/201/265/346/236/242/350/256/260/345/277/206/345/212/250/350/257/215/345/215/217/350/256/256_v1.0-draft.md +172 -0
- package/docs/mdcg//347/216/257/344/272/214_/347/231/275/347/256/261/345/241/253/345/205/205/346/265/201/346/260/264/347/272/277_v0.1.md +31 -0
- package/docs/{ → mdcg/}/347/274/272/345/217/243/345/215/225_P0/346/224/266/345/217/243_v0.1.md +2 -2
- package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_G4-G8/347/274/272/345/217/243/350/243/201/345/256/232/345/215/225_v0.1.md +1 -1
- package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_/347/264/242/345/274/225/344/270/216/345/267/245/347/250/213/350/247/204/350/214/203/345/214/226_/350/256/241/345/210/222_v0.1.md +4 -4
- package/docs/{ → mdcg/}/350/256/260/345/277/206/346/223/215/344/275/234/347/263/273/347/273/237_MdCGOS/344/270/216MCP/346/216/245/345/205/245_v0.1.md +2 -2
- package/docs/mdcg//350/267/250/347/253/257/351/252/214/350/257/201/344/270/216/345/220/214/346/255/245/345/215/217/350/256/256_v0.1.md +93 -0
- package/docs/plans/GridWorld/346/234/200/345/260/217/351/227/255/347/216/257/350/247/204/346/240/274_v0.1.md +176 -0
- package/docs/{ → swarm/}/350/234/202/347/276/244/344/272/222/350/201/224_v0.1.md +3 -3
- package/docs/swarm//350/234/202/347/276/244/345/220/214/351/224/231/346/243/200/346/265/213/345/256/236/351/252/214/345/215/217/350/256/256_v0.1.md +242 -0
- package/docs/theory//345/215/225/347/272/277/347/250/213/344/270/216/346/263/250/346/204/217/345/212/233/351/233/206/344/270/255_/346/227/240/344/272/211/350/256/256/347/220/206/350/256/272/346/226/207/346/241/243_v1.0.md +129 -0
- package/docs/theory//345/271/266/345/217/221/345/277/205/347/204/266/346/200/247/347/220/206/350/256/272_v0.2.md +134 -0
- package/docs/theory//346/246/202/345/277/265/345/210/206/345/261/202/345/257/271/351/275/220/350/241/250_v0.1.md +145 -0
- package/docs/{ → theory/}/347/220/206/350/256/272_/346/234/272/345/210/266_/344/273/243/347/240/201_/345/256/236/351/252/214_/347/274/272/345/217/243/347/237/251/351/230/265_v0.1.md +6 -6
- package/docs/{ → theory/}/347/220/206/350/256/272/344/273/223/346/213/206/345/210/206/344/270/216/347/231/275/347/256/261/347/237/245/350/257/206/345/272/223/345/206/205/350/277/201_v0.1.md +1 -1
- package/docs/theory//350/256/244/347/237/245/344/273/243/347/220/206/344/270/216/346/224/266/346/225/233/347/273/223/346/236/204_/346/235/241/344/273/266/350/256/272/351/207/215/346/236/204_v0.1.md +221 -0
- package/docs/world_model//344/270/226/347/225/214/346/250/241/345/236/213_/347/245/236/347/273/217/347/275/221/347/273/234/345/272/225/345/261/202/346/236/266/346/236/204_v1.0.md +237 -0
- package/docs//345/255/230/347/256/227/344/270/200/344/275/223/346/236/266/346/236/204/345/255/246/344/271/240_/345/244/226/351/203/250/347/220/206/350/256/272/345/257/271/347/205/247/344/270/216/350/267/257/347/272/277/344/272/244/346/216/245_20260916.md +98 -0
- package/docs//345/255/230/347/256/227/344/270/200/344/275/223/347/245/236/347/273/217/347/275/221/347/273/234/346/236/266/346/236/204_/346/200/273/347/272/262/344/270/216/344/272/244/346/216/245_20260916.md +109 -0
- package/docs//345/267/245/344/275/234/347/272/252/345/276/213_/350/256/244/347/237/245/345/233/276/346/235/241/347/233/256_v1.1.json +434 -405
- package/docs//347/201/265/346/236/242/350/207/252/346/210/221/346/224/271/350/277/233/345/267/245/344/275/234/350/256/241/345/210/222_/345/244/226/351/203/250/347/240/224/347/251/266/347/263/273/345/210/227/345/220/270/346/224/266_v1_20260919.md +286 -0
- package/docs//347/231/275/347/256/261/345/214/226/347/272/262/351/242/206_/344/270/211/351/241/271/347/233/256/345/255/246/344/271/240/346/200/273/346/236/266/346/236/204/344/270/216Ghidra/344/272/244/346/216/245_20260916.md +104 -0
- package/docs//350/256/260/345/277/206/350/257/204/345/256/241/347/263/273/347/273/237_/347/253/213/351/241/271/350/256/276/350/256/241/344/270/216/346/226/275/345/267/245/344/272/244/346/216/245_20260915.md +183 -0
- package/dsh/README.md +34 -1
- package/dsh/cordis.yml.example +13 -7
- package/dsh/hive-mcp-probe.mjs +94 -0
- package/dsh/hive-mcp.example.yml +62 -0
- package/dsh/update-lingshu.bat +11 -0
- package/dsh/update-lingshu.ps1 +337 -0
- package/lib/hooks.d.ts +8 -0
- package/lib/hooks.js +27 -24
- package/lib/index.d.ts +4 -2
- package/lib/index.js +29 -6
- package/lib/lib/datapath.d.ts +76 -1
- package/lib/lib/datapath.js +199 -13
- package/lib/lib/mdcg_client.d.ts +6 -3
- package/lib/lib/mdcg_client.js +6 -5
- package/lib/lib/mutual.js +4 -4
- package/lib/lib/prompt_safety.d.ts +48 -0
- package/lib/lib/prompt_safety.js +62 -0
- package/lib/lib/token_store.js +4 -5
- package/md_cg/audit.py +91 -2
- package/md_cg/autonomy.py +86 -15
- package/md_cg/backfill.py +36 -1
- package/md_cg/backfill_bigdomain.py +34 -0
- package/md_cg/bench6_arms.py +28 -1
- package/md_cg/bench6_common.py +10 -1
- package/md_cg/bench6_competitors.py +6 -1
- package/md_cg/bench_axis_domain.py +9 -1
- package/md_cg/bench_blind_comp.py +7 -1
- package/md_cg/bench_en_atoms_public.py +9 -0
- package/md_cg/bench_governance.py +348 -0
- package/md_cg/bench_lme_zh.py +16 -1
- package/md_cg/bench_locomo.py +2 -1
- package/md_cg/bench_locomo_zh.py +16 -1
- package/md_cg/bench_locomo_zh_public.py +4 -1
- package/md_cg/bench_longmem.py +2 -1
- package/md_cg/bench_membench.py +37 -6
- package/md_cg/bench_p0.py +4 -1
- package/md_cg/bench_progressive.py +61 -10
- package/md_cg/bench_role_views.py +238 -0
- package/md_cg/bench_task_ab.py +8 -1
- package/md_cg/bench_task_ab_llm.py +13 -1
- package/md_cg/bench_unified_en.py +6 -1
- package/md_cg/bench_zh_mad.py +20 -1
- package/md_cg/blindspot_tickets.py +123 -0
- package/md_cg/branches.py +286 -0
- package/md_cg/build_postings.py +73 -0
- package/md_cg/ccgc.py +949 -0
- package/md_cg/census.py +5 -1
- package/md_cg/chain.py +24 -3
- package/md_cg/codeindex.py +134 -17
- package/md_cg/coldverify.py +265 -0
- package/md_cg/comment_gate.py +338 -0
- package/md_cg/cond_compose.py +190 -0
- package/md_cg/cond_facts.py +155 -0
- package/md_cg/cond_template.json +107 -0
- package/md_cg/condition_anchor.py +143 -0
- package/md_cg/conformance.py +727 -0
- package/md_cg/consistency.py +25 -2
- package/md_cg/consolidate.py +53 -2
- package/md_cg/corpus.py +5 -1
- package/md_cg/crosscheck.py +42 -2
- package/md_cg/crypto.py +35 -1
- package/md_cg/d_meta.py +310 -0
- package/md_cg/datapath.py +201 -26
- package/md_cg/docindex.py +122 -1
- package/md_cg/eval_common.py +35 -6
- package/md_cg/evidence.py +27 -1
- package/md_cg/evolution.py +21 -1
- package/md_cg/export.py +11 -1
- package/md_cg/forgetting.py +34 -4
- package/md_cg/fsutil.py +81 -2
- package/md_cg/hotcache.py +214 -0
- package/md_cg/hyperedge.py +251 -0
- package/md_cg/identity.py +20 -3
- package/md_cg/insight.py +19 -3
- package/md_cg/lexicon/build_cedict_en_zh.py +9 -0
- package/md_cg/lexicon/build_standard_en.py +171 -168
- package/md_cg/lexicon/expand_en_zh.py +6 -0
- package/md_cg/lifecycle.py +273 -0
- package/md_cg/linkref.py +281 -0
- package/md_cg/links.py +29 -1
- package/md_cg/mcp_server.py +894 -168
- package/md_cg/md_whitebox.py +53 -1
- package/md_cg/mdcg.py +1205 -41
- package/md_cg/mdcos.py +1060 -76
- package/md_cg/metacognition.py +39 -4
- package/md_cg/migrate.py +4 -0
- package/md_cg/migrate_aeis.py +221 -213
- package/md_cg/migrate_roleplay.py +8 -0
- package/md_cg/migrate_wisdom_graph.py +14 -1
- package/md_cg/mreview/__init__.py +25 -0
- package/md_cg/mreview/__main__.py +110 -0
- package/md_cg/mreview/bundle.py +178 -0
- package/md_cg/mreview/candidates.py +262 -0
- package/md_cg/mreview/govern.py +694 -0
- package/md_cg/mreview/locate.py +939 -0
- package/md_cg/mreview/pipeline.py +729 -0
- package/md_cg/mreview/rules/duplication.json +21 -0
- package/md_cg/mreview/rules/field_coverage.json +54 -0
- package/md_cg/mreview/rules/source_license.json +21 -0
- package/md_cg/mreview/rules/template_flow.json +21 -0
- package/md_cg/mreview/ruleset.py +253 -0
- package/md_cg/nodefile.py +269 -1
- package/md_cg/pooling.py +23 -1
- package/md_cg/postings.py +298 -0
- package/md_cg/predict.py +113 -15
- package/md_cg/progressive.py +3 -0
- package/md_cg/protect.py +18 -5
- package/md_cg/protocol.py +372 -0
- package/md_cg/provenance.py +262 -0
- package/md_cg/reach.py +453 -0
- package/md_cg/refindex.py +88 -4
- package/md_cg/refine.py +20 -1
- package/md_cg/roleviews.py +89 -0
- package/md_cg/routing.py +76 -0
- package/md_cg/scrub.py +68 -3
- package/md_cg/security.py +26 -1
- package/md_cg/self_state.py +65 -2
- package/md_cg/selfreport.py +151 -0
- package/md_cg/semantic/canonical.py +5 -0
- package/md_cg/semantic/en_normalizer.py +364 -295
- package/md_cg/semantic/zh_en_atoms.py +139 -136
- package/md_cg/signer.py +41 -1
- package/md_cg/sources.py +583 -547
- package/md_cg/statushdr.py +179 -0
- package/md_cg/stg.py +59 -18
- package/md_cg/subgraph.py +23 -0
- package/md_cg/sustain.py +74 -1
- package/md_cg/tasks.py +471 -0
- package/md_cg/test_action_derive.py +203 -0
- package/md_cg/test_audit_rotate.py +270 -0
- package/md_cg/test_autonomy.py +26 -0
- package/md_cg/test_bench_governance.py +102 -0
- package/md_cg/test_blindspot_tickets.py +166 -0
- package/md_cg/test_branches.py +249 -0
- package/md_cg/test_ccg_perturb.py +1 -1
- package/md_cg/test_ccgc.py +433 -0
- package/md_cg/test_codeindex.py +338 -0
- package/md_cg/test_comment_gate.py +187 -0
- package/md_cg/test_cond_compose_anchors.py +76 -0
- package/md_cg/test_condition_anchor.py +82 -0
- package/md_cg/test_conformance.py +343 -0
- package/md_cg/test_d_meta.py +412 -0
- package/md_cg/test_datapath_root.py +188 -0
- package/md_cg/test_en_pipeline.py +24 -0
- package/md_cg/test_gain_gate.py +47 -1
- package/md_cg/test_health_scale.py +173 -0
- package/md_cg/test_hot_cold.py +187 -0
- package/md_cg/test_hyperedge.py +245 -0
- package/md_cg/test_identity_attribution.py +6 -0
- package/md_cg/test_index_durability.py +224 -0
- package/md_cg/test_lifecycle.py +309 -0
- package/md_cg/test_linkref.py +306 -0
- package/md_cg/test_md_access_parity.py +15 -3
- package/md_cg/test_mr_m1.py +769 -0
- package/md_cg/test_mr_m2.py +587 -0
- package/md_cg/test_mr_m3.py +710 -0
- package/md_cg/test_mr_m4.py +485 -0
- package/md_cg/test_p1.py +1 -1
- package/md_cg/test_p11_consistency.py +1 -1
- package/md_cg/test_p12_metacognition.py +2 -2
- package/md_cg/test_p16_self_state.py +1 -1
- package/md_cg/test_p26_refindex.py +50 -21
- package/md_cg/test_p27_docindex.py +258 -4
- package/md_cg/test_p28_refcheck.py +1 -1
- package/md_cg/test_p29_session_ingest_export.py +1 -1
- package/md_cg/test_p2_mcp.py +7 -1
- package/md_cg/test_p31_insight.py +24 -0
- package/md_cg/test_p38_contextualize.py +1 -1
- package/md_cg/test_p39_vision_evidence.py +1 -1
- package/md_cg/test_p40_refine_worklist.py +1 -1
- package/md_cg/test_p41_evolve_patrol.py +1 -1
- package/md_cg/test_p42_provenance.py +1 -1
- package/md_cg/test_p43_pooling.py +41 -13
- package/md_cg/test_p44_md_whitebox.py +14 -1
- package/md_cg/test_protocol.py +243 -0
- package/md_cg/test_reach.py +378 -0
- package/md_cg/test_reach_keys.py +201 -0
- package/md_cg/test_reach_meta_exits.py +145 -0
- package/md_cg/test_read_clip.py +141 -0
- package/md_cg/test_retr_s1.py +340 -0
- package/md_cg/test_retr_s1b.py +209 -0
- package/md_cg/test_retr_s3.py +194 -0
- package/md_cg/test_retr_s4.py +163 -0
- package/md_cg/test_retr_s5.py +200 -0
- package/md_cg/test_retr_s6.py +157 -0
- package/md_cg/test_retr_s7.py +385 -0
- package/md_cg/test_retr_s8_time.py +316 -0
- package/md_cg/test_retr_s9_edges.py +286 -0
- package/md_cg/test_retr_s9_entity_ctx.py +175 -0
- package/md_cg/test_review_conformance.py +367 -0
- package/md_cg/test_role_views.py +354 -0
- package/md_cg/test_tasks.py +409 -0
- package/md_cg/test_tool_face.py +189 -0
- package/md_cg/test_trust.py +361 -0
- package/md_cg/test_twophase.py +286 -0
- package/md_cg/test_units_poll.py +71 -0
- package/md_cg/test_v14_fixes.py +397 -0
- package/md_cg/test_validity_filter.py +280 -0
- package/md_cg/test_wisdom_md_store.py +7 -3
- package/md_cg/test_writepipe.py +214 -0
- package/md_cg/theory.py +17 -2
- package/md_cg/tokens.py +134 -12
- package/md_cg/tool_face.py +261 -0
- package/md_cg/trust.py +943 -0
- package/md_cg/twophase.py +232 -0
- package/md_cg/units.py +665 -0
- package/md_cg/vision_evidence.py +25 -2
- package/md_cg/weights.py +25 -2
- package/md_cg/whitebox.py +33 -2
- package/md_cg/whitebox_kb/data/verify_cache.json +21233 -360
- package/md_cg/whitebox_kb/data/verify_savings.jsonl +5124 -0
- package/md_cg/whitebox_kb/wisdom/audit_log/chain_heat.json +10 -10
- package/md_cg/whitebox_kb/wisdom/code_compose.py +113 -6
- package/md_cg/whitebox_kb/wisdom/code_solidified.json +1 -1
- package/md_cg/whitebox_kb/wisdom/verifier.py +340 -55
- package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db +0 -0
- package/md_cg/writelimit.py +37 -7
- package/md_cg/writepipe.py +543 -0
- package/package.json +2 -2
- package/skills/skills/designer-perspective/scripts/__pycache__/designer.cpython-310.pyc +0 -0
- package/skills/skills/designer-perspective/scripts/designer.py +17 -1
- package/skills/skills/designer-perspective/tests/selftest.py +3 -1
- package/src/hooks.ts +27 -22
- package/src/index.ts +33 -6
- package/src/lib/datapath.ts +211 -13
- package/src/lib/mdcg_client.ts +12 -8
- package/src/lib/mutual.ts +411 -411
- package/src/lib/prompt_safety.ts +62 -0
- package/src/lib/token_store.ts +4 -5
- package/zcode/AGENTS.md +21 -10
- package/zcode/README.md +4 -0
- package/docs//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +0 -221
- /package/docs/{AGI → eval/AGI}/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v1.0.md" +0 -0
- /package/docs/{AGI → eval/AGI}/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v2.0.md" +0 -0
- /package/docs/{ → eval/}/345/256/236/351/252/214/346/226/271/346/241/210_/345/255/246/344/271/240/351/227/255/347/216/257AB/344/270/216/346/250/252/350/257/204_v1.0.md" +0 -0
- /package/docs/{ → eval/}/346/250/252/350/257/204_/345/205/255/345/256/266100/351/242/230/344/270/255/350/213/261/345/217/214/346/237/245_v1.0.md" +0 -0
- /package/docs/{guardrail-charter.md → mdcg/guardrail-charter.md} +0 -0
- /package/docs/{lingshu_tutorial.html → mdcg/lingshu_tutorial.html} +0 -0
- /package/docs/{memory-assessment.html → mdcg/memory-assessment.html} +0 -0
- /package/docs/{memory_score.html → mdcg/memory_score.html} +0 -0
- /package/docs/{memory_score.png → mdcg/memory_score.png} +0 -0
- /package/docs/{release_v0.3.0.md → mdcg/release_v0.3.0.md} +0 -0
- /package/docs/{release_v0.4.5.md → mdcg/release_v0.4.5.md} +0 -0
- /package/docs/{tool_table_v0.3.0.md → mdcg/tool_table_v0.3.0.md} +0 -0
- /package/docs/{ → mdcg/}/344/273/244/347/211/214/344/270/216/350/247/222/350/211/262/346/235/203/350/201/214/345/210/206/347/246/273_v0.1.md" +0 -0
- /package/docs/{ → mdcg/}/347/201/265/346/236/24282/345/267/245/345/205/267_/345/212/237/350/203/275/346/225/264/347/220/206/344/270/216/350/277/201/347/247/273/346/230/240/345/260/204_v0.1.md" +0 -0
- /package/docs/{ → mdcg/}/347/201/265/346/236/242MCP/345/267/245/345/205/267/346/200/273/350/241/250_v3.4.md" +0 -0
- /package/docs/{ → mdcg/}/347/201/265/346/236/242_/350/207/252/346/210/221/345/261/202/345/256/232/344/271/211.md" +0 -0
- /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_MD/347/233/256/345/275/225/346/226/271/346/241/210_v0.1.md" +0 -0
- /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276_/346/235/241/344/273/266/347/251/272/351/227/264/345/220/210/346/210/220/344/270/216/347/224/237/346/225/210/346/235/241/344/273/266/345/217/243/345/276/204_v0.1.md" +0 -0
- /package/docs/{ → mdcg/}/350/256/244/347/237/245/345/233/276/344/275/234/344/270/272/350/256/260/345/277/206/346/223/215/344/275/234/347/263/273/347/273/237_/350/257/204/344/274/260/344/270/216/350/267/257/347/272/277_v0.1.md" +0 -0
- /package/docs/{ → plans/}/345/221/275/345/220/215/346/262/273/347/220/206_/351/241/271/347/233/256/350/256/241/345/210/222.md" +0 -0
- /package/docs/{ → plans/}/347/237/245/350/257/206/345/233/276/350/260/261/351/241/271/347/233/256_/344/272/244/346/216/245/346/226/207/346/241/243_20260914.md" +0 -0
- /package/docs/{ → swarm/}/350/234/202/347/276/244/345/244/232/346/231/272/350/203/275/344/275/223_/344/275/277/347/224/250/346/212/245/345/221/212_20260913.md" +0 -0
- /package/docs/{ → swarm/}/350/234/202/347/276/244/345/244/232/346/231/272/350/203/275/344/275/223_/345/212/237/350/203/275/350/257/264/346/230/216_v0.6.md" +0 -0
- /package/docs/{ → swarm/}/350/234/202/347/276/244/347/233/262/345/214/272/346/240/207/350/256/260_v1.0.md" +0 -0
- /package/docs/{ → theory/}/344/277/241/346/201/257/345/267/256/344/270/272/344/273/200/344/271/210/345/277/205/347/204/266/345/255/230/345/234/250/344/270/224/350/207/252/347/204/266/346/211/251/345/244/247.md" +0 -0
- /package/docs/{ → theory/}/346/231/272/350/203/275/347/232/204/345/205/254/347/220/206/345/214/226/345/237/272/347/237/263.md" +0 -0
- /package/docs/{ → theory/}/346/231/272/350/203/275/347/232/204/350/256/244/347/237/245/350/277/207/347/250/213.md" +0 -0
- /package/docs/{ → theory/}/346/231/272/350/203/275/350/256/2723.4.md" +0 -0
- /package/docs/{ → theory/}/347/231/275/347/256/261/346/231/272/350/203/275/346/230/257/344/273/200/344/271/210/357/274/237.md" +0 -0
- /package/docs/{ → theory/}/347/231/275/347/256/261/346/231/272/350/203/275/347/263/273/345/210/227/302/267/347/254/254/344/272/224/347/257/207/357/274/232/350/256/251AI/347/234/237/346/255/243/350/243/205/344/270/212/350/256/260/345/277/206.md" +0 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""md_cg · 冷路径异步深度验证队列
|
|
3
|
+
|
|
4
|
+
【为什么】写入路径中的一跳同步传播(_after_trust → mark_dependents)
|
|
5
|
+
只做「标记存疑」——它不验证下游是否真的被影响。真正的深度验证
|
|
6
|
+
需要:(1) 重跑 judge_qualification 看条件是否仍命中;
|
|
7
|
+
(2) 检查依赖链上的验证态是否级联失效。
|
|
8
|
+
|
|
9
|
+
这些操作可重可慢,不该阻塞写入路径。故异步入队,后台消费。
|
|
10
|
+
|
|
11
|
+
【设计】
|
|
12
|
+
- enqueue(node_id, action, **kw):入队异步验证任务
|
|
13
|
+
- 后台线程消费队列,调 trust.set_state + judge_ranking
|
|
14
|
+
- 队列落盘 _coldverify.jsonl(崩溃恢复)
|
|
15
|
+
- 默认不启动后台线程(opt-in:start_worker())
|
|
16
|
+
- 也可同步消费(drain(),用于测试)
|
|
17
|
+
|
|
18
|
+
【边界】
|
|
19
|
+
- 不阻塞写入路径(_after_trust 只 enqueue 不等结果)
|
|
20
|
+
- 后台线程异常只记日志不抛(永不拖垮主进程)
|
|
21
|
+
- 队列文件可选(无文件时纯内存,适合测试)
|
|
22
|
+
|
|
23
|
+
零第三方依赖(D-005)。
|
|
24
|
+
"""
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import json
|
|
28
|
+
import os
|
|
29
|
+
import threading
|
|
30
|
+
import time
|
|
31
|
+
from collections import deque
|
|
32
|
+
|
|
33
|
+
#: 队列文件名
|
|
34
|
+
QUEUE_FILE = "_coldverify.jsonl"
|
|
35
|
+
#: 后台线程轮询间隔(秒)
|
|
36
|
+
POLL_INTERVAL = 2.0
|
|
37
|
+
#: 单次批处理上限
|
|
38
|
+
BATCH_LIMIT = 10
|
|
39
|
+
|
|
40
|
+
_VALID_ACTIONS = {"reverify", "propagate_depth", "patrol_check"}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ColdVerifyQueue:
|
|
44
|
+
"""冷路径异步深度验证队列。
|
|
45
|
+
|
|
46
|
+
线程安全:enqueue/drain/status 可跨线程调用。
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(self, root=None):
|
|
50
|
+
self._root = root
|
|
51
|
+
self._queue: deque = deque()
|
|
52
|
+
self._lock = threading.Lock()
|
|
53
|
+
self._worker = None
|
|
54
|
+
self._stop = threading.Event()
|
|
55
|
+
self._stats = {"enqueued": 0, "processed": 0, "errors": 0,
|
|
56
|
+
"skipped": 0}
|
|
57
|
+
self._queue_path = (os.path.join(root, QUEUE_FILE)
|
|
58
|
+
if root else None)
|
|
59
|
+
self._load_persisted()
|
|
60
|
+
|
|
61
|
+
def _load_persisted(self):
|
|
62
|
+
"""从队列文件恢复未处理任务(崩溃恢复)。"""
|
|
63
|
+
if not self._queue_path or not os.path.exists(self._queue_path):
|
|
64
|
+
return
|
|
65
|
+
try:
|
|
66
|
+
with open(self._queue_path, "r", encoding="utf-8") as f:
|
|
67
|
+
for line in f:
|
|
68
|
+
line = line.strip()
|
|
69
|
+
if not line:
|
|
70
|
+
continue
|
|
71
|
+
task = json.loads(line)
|
|
72
|
+
if not task.get("_done"):
|
|
73
|
+
self._queue.append(task)
|
|
74
|
+
except Exception: # noqa: BLE001
|
|
75
|
+
pass # 崩溃恢复容错:文件损坏就不恢复
|
|
76
|
+
|
|
77
|
+
def _persist(self):
|
|
78
|
+
"""持久化当前队列(全量覆写)。"""
|
|
79
|
+
if not self._queue_path:
|
|
80
|
+
return
|
|
81
|
+
try:
|
|
82
|
+
with open(self._queue_path, "w", encoding="utf-8") as f:
|
|
83
|
+
for task in self._queue:
|
|
84
|
+
f.write(json.dumps(task, ensure_ascii=False) + "\n")
|
|
85
|
+
except Exception: # noqa: BLE001
|
|
86
|
+
pass # 持久化失败不影响内存队列
|
|
87
|
+
|
|
88
|
+
def enqueue(self, node_id: str, action: str = "reverify", **kw):
|
|
89
|
+
"""入队异步验证任务。返回 task dict。"""
|
|
90
|
+
if action not in _VALID_ACTIONS:
|
|
91
|
+
raise ValueError(f"未知 action: {action},合法: {_VALID_ACTIONS}")
|
|
92
|
+
task = {
|
|
93
|
+
"node_id": node_id,
|
|
94
|
+
"action": action,
|
|
95
|
+
"enqueued_at": time.time(),
|
|
96
|
+
"kwargs": kw,
|
|
97
|
+
}
|
|
98
|
+
with self._lock:
|
|
99
|
+
self._queue.append(task)
|
|
100
|
+
self._stats["enqueued"] += 1
|
|
101
|
+
self._persist()
|
|
102
|
+
return task
|
|
103
|
+
|
|
104
|
+
def drain(self, cg, *, limit=BATCH_LIMIT):
|
|
105
|
+
"""同步消费队列(用于测试/手动处理)。返回处理结果列表。"""
|
|
106
|
+
results = []
|
|
107
|
+
with self._lock:
|
|
108
|
+
batch = []
|
|
109
|
+
for _ in range(min(limit, len(self._queue))):
|
|
110
|
+
batch.append(self._queue.popleft())
|
|
111
|
+
for task in batch:
|
|
112
|
+
try:
|
|
113
|
+
r = self._process(cg, task)
|
|
114
|
+
results.append(r)
|
|
115
|
+
self._stats["processed"] += 1
|
|
116
|
+
except Exception as exc: # noqa: BLE001
|
|
117
|
+
self._stats["errors"] += 1
|
|
118
|
+
results.append({"node_id": task["node_id"],
|
|
119
|
+
"action": task["action"],
|
|
120
|
+
"error": str(exc),
|
|
121
|
+
"ok": False})
|
|
122
|
+
with self._lock:
|
|
123
|
+
self._persist()
|
|
124
|
+
return results
|
|
125
|
+
|
|
126
|
+
def _process(self, cg, task):
|
|
127
|
+
"""执行单个验证任务。"""
|
|
128
|
+
from . import trust
|
|
129
|
+
nid = task["node_id"]
|
|
130
|
+
action = task["action"]
|
|
131
|
+
kw = task.get("kwargs", {})
|
|
132
|
+
|
|
133
|
+
if action == "reverify":
|
|
134
|
+
# 重新验证单节点:重跑 judge_qualification
|
|
135
|
+
node = cg.get(nid)
|
|
136
|
+
if not node:
|
|
137
|
+
self._stats["skipped"] += 1
|
|
138
|
+
return {"node_id": nid, "action": action, "ok": True,
|
|
139
|
+
"skipped": "node_not_found"}
|
|
140
|
+
fm = node.get("frontmatter") or {}
|
|
141
|
+
old_state = trust.state_of(fm)
|
|
142
|
+
# 只对非 unverified 节点做深度验证
|
|
143
|
+
if old_state == "unverified":
|
|
144
|
+
self._stats["skipped"] += 1
|
|
145
|
+
return {"node_id": nid, "action": action, "ok": True,
|
|
146
|
+
"skipped": "unverified_no_action"}
|
|
147
|
+
# 检查时效
|
|
148
|
+
kind, _, _ = trust.validity(fm)
|
|
149
|
+
want, why = None, ""
|
|
150
|
+
if kind == "expired" and old_state != "expired":
|
|
151
|
+
want, why = "expired", "冷路径:时效过期"
|
|
152
|
+
elif kind == "not_yet":
|
|
153
|
+
want, why = "unverified", "冷路径:尚未生效"
|
|
154
|
+
if want is None:
|
|
155
|
+
return {"node_id": nid, "action": action, "ok": True,
|
|
156
|
+
"old_state": old_state, "new_state": old_state,
|
|
157
|
+
"changed": False}
|
|
158
|
+
# 迁移结果**必须检查**(2026-09-20 v14 缺陷 D 修复):`trust.set_state`
|
|
159
|
+
# 对非法迁移返回 ok=False(负路由不抛异常),旧实现丢弃返回值后一律
|
|
160
|
+
# 上报 `ok=True + new_state=<请求值>` —— 恰好在本队列最该说话的两条
|
|
161
|
+
# 迁移上(doubted→expired / verified→unverified,均为 TRANSITIONS
|
|
162
|
+
# 明令拒绝的跳级)**说了假话**,且 stats.errors 恒 0 把它盖住。
|
|
163
|
+
# trust 层做对了(拒绝非法迁移),队列层不得把它翻译成成功。
|
|
164
|
+
r = trust.set_state(cg, nid, want, reason=why,
|
|
165
|
+
actor="coldverify", **kw)
|
|
166
|
+
if not r.get("ok"):
|
|
167
|
+
self._stats["errors"] += 1
|
|
168
|
+
return {"node_id": nid, "action": action, "ok": False,
|
|
169
|
+
"old_state": old_state, "requested_state": want,
|
|
170
|
+
"error": "transition_rejected:%s" % r.get("error"),
|
|
171
|
+
"reason": r.get("reason") or "",
|
|
172
|
+
"detail": "非法迁移被 trust.TRANSITIONS 拒绝,状态未变"}
|
|
173
|
+
return {"node_id": nid, "action": action, "ok": True,
|
|
174
|
+
"old_state": old_state, "new_state": want,
|
|
175
|
+
"changed": bool(r.get("changed"))}
|
|
176
|
+
|
|
177
|
+
elif action == "propagate_depth":
|
|
178
|
+
# 多跳深度传播
|
|
179
|
+
r = trust.propagate(cg, apply=True, actor="coldverify",
|
|
180
|
+
**kw)
|
|
181
|
+
return {"node_id": nid, "action": action, "ok": True,
|
|
182
|
+
"propagation": r}
|
|
183
|
+
|
|
184
|
+
elif action == "patrol_check":
|
|
185
|
+
# 巡检式检查
|
|
186
|
+
rep = trust.patrol(cg, **kw)
|
|
187
|
+
return {"node_id": nid, "action": action, "ok": True,
|
|
188
|
+
"patrol": rep}
|
|
189
|
+
|
|
190
|
+
return {"node_id": nid, "action": action, "ok": False,
|
|
191
|
+
"error": "unknown_action"}
|
|
192
|
+
|
|
193
|
+
def start_worker(self, cg, *, poll_interval=POLL_INTERVAL):
|
|
194
|
+
"""启动后台消费线程。"""
|
|
195
|
+
if self._worker and self._worker.is_alive():
|
|
196
|
+
return self._worker
|
|
197
|
+
self._stop.clear()
|
|
198
|
+
|
|
199
|
+
def _run():
|
|
200
|
+
while not self._stop.is_set():
|
|
201
|
+
try:
|
|
202
|
+
if self._queue:
|
|
203
|
+
self.drain(cg, limit=BATCH_LIMIT)
|
|
204
|
+
except Exception: # noqa: BLE001
|
|
205
|
+
self._stats["errors"] += 1
|
|
206
|
+
self._stop.wait(poll_interval)
|
|
207
|
+
|
|
208
|
+
self._worker = threading.Thread(target=_run, daemon=True,
|
|
209
|
+
name="coldverify-worker")
|
|
210
|
+
self._worker.start()
|
|
211
|
+
return self._worker
|
|
212
|
+
|
|
213
|
+
def stop_worker(self, timeout=5.0):
|
|
214
|
+
"""停止后台线程。"""
|
|
215
|
+
self._stop.set()
|
|
216
|
+
if self._worker and self._worker.is_alive():
|
|
217
|
+
self._worker.join(timeout=timeout)
|
|
218
|
+
self._worker = None
|
|
219
|
+
|
|
220
|
+
def status(self):
|
|
221
|
+
"""返回队列状态。"""
|
|
222
|
+
with self._lock:
|
|
223
|
+
return {
|
|
224
|
+
"queue_size": len(self._queue),
|
|
225
|
+
"stats": dict(self._stats),
|
|
226
|
+
"worker_alive": (self._worker is not None
|
|
227
|
+
and self._worker.is_alive()),
|
|
228
|
+
"queue_file": self._queue_path,
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
def clear(self):
|
|
232
|
+
"""清空队列(测试用)。"""
|
|
233
|
+
with self._lock:
|
|
234
|
+
self._queue.clear()
|
|
235
|
+
self._persist()
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
#: 进程级默认实例
|
|
239
|
+
_DEFAULT = None
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def default_queue(root=None):
|
|
243
|
+
"""进程级默认冷路径队列单例。"""
|
|
244
|
+
global _DEFAULT
|
|
245
|
+
if _DEFAULT is None:
|
|
246
|
+
_DEFAULT = ColdVerifyQueue(root=root)
|
|
247
|
+
return _DEFAULT
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def attach(cg):
|
|
251
|
+
"""给 cg 实例挂冷路径队列(幂等)。"""
|
|
252
|
+
if not hasattr(cg, "_coldverify") or cg._coldverify is None:
|
|
253
|
+
cg._coldverify = ColdVerifyQueue(root=cg.root)
|
|
254
|
+
return cg._coldverify
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def get(cg):
|
|
258
|
+
"""取 cg 实例的冷路径队列(未挂返回 None)。"""
|
|
259
|
+
return getattr(cg, "_coldverify", None)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def enqueue(cg, node_id: str, action: str = "reverify", **kw):
|
|
263
|
+
"""快捷入口:挂队列 + 入队。"""
|
|
264
|
+
q = attach(cg)
|
|
265
|
+
return q.enqueue(node_id, action, **kw)
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""comment_gate · 代码符号「条件化注释」抽样闸门(计划四环之环二入口)。
|
|
3
|
+
|
|
4
|
+
**换对象不换机制**:复用 refine.py 的闸门范式(分层抽样 → 只读工单 → 人工裁决留痕 →
|
|
5
|
+
通过率放行),把处理对象从「node_ 前缀的记忆节点 CCG 字段缺口」换成
|
|
6
|
+
「code_ 前缀的代码符号注释缺口」。
|
|
7
|
+
|
|
8
|
+
候选判据(唯一、机械、不做语义猜测):**代码节点且正文缺『生效条件』**。
|
|
9
|
+
依 Phase 0 契约,代码节点的生效条件只能来自源码人工声明——缺它即 BLINDSPOT
|
|
10
|
+
(缺证据),正是本闸门要治理的对象。落点按使用者裁决 q-0:写进源码、定义行紧邻的
|
|
11
|
+
井号注释(**两个窗口**,见 docs/mdcg/代码评审与条件化注释_契约_v0.1.md §三.2)。
|
|
12
|
+
|
|
13
|
+
本模块只做**候选池 / 工单 / 留痕 / 闸门**:不生成注释、不改任何节点。
|
|
14
|
+
生成与评审方式按 q-2(LLM 生成 + 人工抽检,复用 0.90 闸门)。
|
|
15
|
+
|
|
16
|
+
诚实边界(honest_limits 已随 SPEC 一并输出):
|
|
17
|
+
· 分层抽样的**分配**沿用 refine.sample_ids 对 code_ 节点的口径(家族=大域),
|
|
18
|
+
而非对候选池重新分配——故 sample_adequacy 会如实报出样本里的候选产出率;
|
|
19
|
+
若产出率不足,应先扩大 n 或改用候选池重分配(已知待办,不在本片)。
|
|
20
|
+
"""
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import json
|
|
24
|
+
import os
|
|
25
|
+
import time
|
|
26
|
+
|
|
27
|
+
from . import codeindex, nodefile, refine
|
|
28
|
+
|
|
29
|
+
#: 放行阈值**唯一真源在 refine**(不在此处再定义一份,防口径漂移)
|
|
30
|
+
GATE_MIN_PASS_RATE = refine.GATE_MIN_PASS_RATE
|
|
31
|
+
SAMPLE_N = refine.SAMPLE_N
|
|
32
|
+
#: 本闸门自己的抽样种子(与 refine 的 g6-sample-v1 分离,样本可各自复算)
|
|
33
|
+
SAMPLE_SEED = "comment-gate-v1"
|
|
34
|
+
#: 代码节点 id 前缀(见 codeindex.node_id = code_ + sha1 前 12 位)
|
|
35
|
+
PREFIX = "code_"
|
|
36
|
+
LOG_NAME = "_comment_gate.jsonl"
|
|
37
|
+
|
|
38
|
+
#: 人工核对清单(与工单逐项对应;对照 refine.SPEC.review_items 的同构位置)
|
|
39
|
+
REVIEW_ITEMS = (
|
|
40
|
+
"生效条件是否为**功能前置条件**(何种输入/状态下正确),而非索引元条件",
|
|
41
|
+
"条件可否被机械复核(有输入/状态判据;不是「常用条件默认省略」)",
|
|
42
|
+
"落点是否为源码定义行紧邻的井号注释(两窗口之一),且不覆盖既有实现说明",
|
|
43
|
+
"公开仓合规:过第 14 条「内容政策 + 隐私」双清单(补写内容随源码公开)",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
SPEC = {
|
|
47
|
+
"goal": "为代码符号补写功能级生效条件注释,使其在检索侧可判(不再因缺证据恒 BLINDSPOT)",
|
|
48
|
+
"target": "code_ 前缀节点中正文缺『生效条件』者",
|
|
49
|
+
"landing": "源码定义行紧邻的井号注释(leading/body 两窗口,物理序合并)",
|
|
50
|
+
"review_items": list(REVIEW_ITEMS),
|
|
51
|
+
"gate": {"min_pass_rate": GATE_MIN_PASS_RATE, "basis": "人工核对忠实比例",
|
|
52
|
+
"rule": "低于阈值不得扩批"},
|
|
53
|
+
"honest_limits": [
|
|
54
|
+
"本闸门只覆盖已索引的代码节点;未索引的源码不在面内(先跑 index_code)",
|
|
55
|
+
"分层分配沿用 code_ 节点口径而非候选池,样本候选产出率由 sample_adequacy 如实上报",
|
|
56
|
+
"不生成注释、不改节点:生成与评审属另一环节(LLM 生成 + 人工抽检)",
|
|
57
|
+
],
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# 生效条件:cg 传入后返回 os.path.join(cg.root, LOG_NAME),即以 cg.root 与模块级常量 LOG_NAME 拼接的日志路径(cg 缺 root 属性时抛 AttributeError)。
|
|
62
|
+
def _log_path(cg) -> str:
|
|
63
|
+
return os.path.join(cg.root, LOG_NAME)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# 生效条件:cg 与 nid 传入后,先看 str(nid) 是否以模块级常量 PREFIX 开头(不以则返回 False);以 PREFIX 开头时取 cg.get(nid)(缺节点按空字典)的 content(假值按空串)经 nodefile.ccg_completeness 判断,若 "生效条件" 不在其 required_present 中则返回 True,否则 False。
|
|
67
|
+
def is_candidate(cg, nid) -> bool:
|
|
68
|
+
"""候选判据:代码节点且正文缺『生效条件』(机械判据,唯一)。"""
|
|
69
|
+
if not str(nid).startswith(PREFIX):
|
|
70
|
+
return False
|
|
71
|
+
node = cg.get(nid) or {}
|
|
72
|
+
comp = nodefile.ccg_completeness(node.get("content") or "")
|
|
73
|
+
return "生效条件" not in comp["required_present"]
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# 生效条件:cg 与 nid 传入后,从 cg.get(nid)(缺节点按空字典)的 frontmatter(假值按空字典)的 code_ref(假值按空字典)中按 path/name/kind/lineno/end/lang/precise 各键取 ref.get(k)(缺键为 None),返回含 code_ref 与固定 landing_rule、landing_note 字段的落点字典。
|
|
77
|
+
def _landing(cg, nid) -> dict:
|
|
78
|
+
"""工单条目 → 源码落点(坐标 + 落点规则),供补写者直接定位。"""
|
|
79
|
+
node = cg.get(nid) or {}
|
|
80
|
+
fm = node.get("frontmatter") or {}
|
|
81
|
+
ref = fm.get("code_ref") or {}
|
|
82
|
+
return {
|
|
83
|
+
"code_ref": {k: ref.get(k) for k in
|
|
84
|
+
("path", "name", "kind", "lineno", "end", "lang", "precise")},
|
|
85
|
+
"landing_rule": "定义行紧邻上方连续井号注释(leading)或定义行紧邻下方、体首语句之前(body)",
|
|
86
|
+
"landing_note": "两窗口按源码物理行序合并;靠前者胜出(契约 §三.2)",
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# 生效条件:cg 与 nid 传入后,取 cg.get(nid)(缺节点按空字典)的 content(假值按空串)算长度与 refine._sha(content)[:16] 作为 source_sha,并结合 refine._entry(cg, nid) 的 layer/tags(tags 假值按空列表)与 nodefile.CCG_MARKS 得出 ccg_missing,最后合并 _landing(cg, nid) 的返回构成工单条目字典。
|
|
91
|
+
def _item(cg, nid) -> dict:
|
|
92
|
+
node = cg.get(nid) or {}
|
|
93
|
+
content = node.get("content") or ""
|
|
94
|
+
comp = nodefile.ccg_completeness(content)
|
|
95
|
+
e = refine._entry(cg, nid)
|
|
96
|
+
it = {
|
|
97
|
+
"id": nid, "family": refine._family(cg, nid),
|
|
98
|
+
"layer": e.get("layer"), "tags": list(e.get("tags") or []),
|
|
99
|
+
"ccg_present": comp["present"],
|
|
100
|
+
"ccg_missing": [m for m in nodefile.CCG_MARKS if m not in comp["present"]],
|
|
101
|
+
"body_len": len(content),
|
|
102
|
+
"source_sha": refine._sha(content)[:16],
|
|
103
|
+
}
|
|
104
|
+
it.update(_landing(cg, nid))
|
|
105
|
+
return it
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# 生效条件:ids 非空时返回经 is_candidate(cg, i) 过滤后的显式候选与 meta.source='explicit_ids';ids 为空时经 refine._pool(cg, PREFIX) 扫描返回候选与 meta.source='scan'(含 skipped_protected)。
|
|
109
|
+
def candidates(cg, ids=None):
|
|
110
|
+
"""候选池(只读)→ (ids, meta)。"""
|
|
111
|
+
if ids:
|
|
112
|
+
pool = sorted({str(i) for i in ids if is_candidate(cg, i)})
|
|
113
|
+
return pool, {"source": "explicit_ids", "pool": len(pool),
|
|
114
|
+
"requested": len(pool), "candidates": len(pool)}
|
|
115
|
+
all_ids, protected = refine._pool(cg, PREFIX)
|
|
116
|
+
cands = sorted(i for i in all_ids if is_candidate(cg, i))
|
|
117
|
+
return cands, {"source": "scan", "prefix": PREFIX, "pool": len(all_ids),
|
|
118
|
+
"skipped_protected": protected, "candidates": len(cands)}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# 生效条件:seed 为假值(None/空串)时回落模块常量 SAMPLE_SEED,n 仅当为 None 时取 SAMPLE_N、否则 int(n)(n=0 保留 0);ids 为真值时样本取全部候选,为假值(含空列表)时经 refine.sample_ids 抽样后按 is_candidate 过滤。
|
|
122
|
+
def plan(x, ids=None, n=None, seed=None) -> dict:
|
|
123
|
+
"""抽检工单(只读):确定性样本 + 源码落点 + 口径声明 + 样本充分性。"""
|
|
124
|
+
cg = refine._as_cg(x)
|
|
125
|
+
seed = seed or SAMPLE_SEED
|
|
126
|
+
n = SAMPLE_N if n is None else int(n)
|
|
127
|
+
cands, cmeta = candidates(cg, ids=ids)
|
|
128
|
+
if ids:
|
|
129
|
+
sample = sorted(cands)
|
|
130
|
+
smeta = {"pool": len(cands), "sampled": len(cands), "families": 0, "strata": {}}
|
|
131
|
+
else:
|
|
132
|
+
picked, smeta = refine.sample_ids(cg, n=n, seed=seed, prefix=PREFIX)
|
|
133
|
+
sample = sorted(i for i in picked if is_candidate(cg, i))
|
|
134
|
+
items = [_item(cg, nid) for nid in sample]
|
|
135
|
+
strata = {}
|
|
136
|
+
for it in items:
|
|
137
|
+
s = strata.setdefault(it["family"], {"picked": 0, "missing_fields": {}})
|
|
138
|
+
s["picked"] += 1
|
|
139
|
+
for m in it["ccg_missing"]:
|
|
140
|
+
s["missing_fields"][m] = s["missing_fields"].get(m, 0) + 1
|
|
141
|
+
adequacy = {
|
|
142
|
+
"sample_of_code_nodes": smeta.get("sampled", len(sample)),
|
|
143
|
+
"candidates_in_sample": len(sample),
|
|
144
|
+
"candidate_yield": round(len(sample) / float(smeta.get("sampled") or 1), 4),
|
|
145
|
+
"note": "分配沿用 code_ 节点口径;产出率不足时应扩大 n 或改候选池重分配",
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
"root": cg.root, "dry_run": True, "readonly": True,
|
|
149
|
+
"action": "comment_gate", "op": "maintain",
|
|
150
|
+
"prefix": PREFIX, "seed": seed, "requested": n,
|
|
151
|
+
"pool": cmeta, "sampled": len(items), "families": len(strata),
|
|
152
|
+
"sample": sample, "sample_sha": refine._sha(*sample)[:16] if sample else "",
|
|
153
|
+
"strata": strata, "items": items, "worklist": items,
|
|
154
|
+
"spec": SPEC, "gate_rule": SPEC["gate"], "sample_adequacy": adequacy,
|
|
155
|
+
"note": ("代码注释补写工单(只读):供人工核对补写口径;"
|
|
156
|
+
"核对通过率未达阈值前不得扩批。本动作不改任何节点。"),
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# 生效条件:verdicts(None 按 [])中可哈希且属于 okv 字面集合(True/"1"/"true"/"True"/"pass"/"PASS"/"faithful"/"忠实"/"accept"/"ACCEPT")的项计 passed,dict 项在 `v in okv` 处不可哈希先抛 TypeError,故源码里 v.get("verdict") 的计数分支不可达;reviewed 为 0 时 rate=0.0、expand_allowed=False、reason="no_review",否则按 rate 与模块常量 GATE_MIN_PASS_RATE 比较给出 expand_allowed 与 reason。
|
|
161
|
+
def _stats(verdicts) -> dict:
|
|
162
|
+
"""通过率(只认忠实/pass/True),阈值取 refine 唯一真源。"""
|
|
163
|
+
vs = list(verdicts or [])
|
|
164
|
+
okv = {True, "1", "true", "True", "pass", "PASS", "faithful", "忠实",
|
|
165
|
+
"accept", "ACCEPT"}
|
|
166
|
+
passed = 0
|
|
167
|
+
for v in vs:
|
|
168
|
+
if v in okv:
|
|
169
|
+
passed += 1
|
|
170
|
+
elif isinstance(v, dict) and v.get("verdict") in okv:
|
|
171
|
+
passed += 1
|
|
172
|
+
reviewed = len(vs)
|
|
173
|
+
rate = (passed / float(reviewed)) if reviewed else 0.0
|
|
174
|
+
allowed = reviewed > 0 and rate >= GATE_MIN_PASS_RATE
|
|
175
|
+
return {"reviewed": reviewed, "passed": passed, "pass_rate": round(rate, 4),
|
|
176
|
+
"min_pass_rate": GATE_MIN_PASS_RATE, "expand_allowed": allowed,
|
|
177
|
+
"reason": ("" if allowed else
|
|
178
|
+
("no_review" if reviewed == 0 else
|
|
179
|
+
"rate %.4f < %.2f" % (rate, GATE_MIN_PASS_RATE)))}
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
# 生效条件:x 传入后经 refine._as_cg 得到 cg,若 cg.principal 非 None 则调用其 require_admin("maintain_comment_gate");随后调用 plan(cg, ids=ids, n=n, seed=seed) 取工单、调用 _stats(verdicts) 取闸门统计,batch 假值回落 time.strftime("%Y%m%d-%H%M%S"),os.makedirs(cg.root, exist_ok=True) 后把含 batch/actor/seed/pool/sample/verdicts/gate 等字段的记录以追加方式写入 _log_path(cg),并返回 ok=True 的留痕结果。
|
|
183
|
+
def apply(x, ids=None, n=None, seed=None, verdicts=None, actor=None, note=None,
|
|
184
|
+
batch=None) -> dict:
|
|
185
|
+
"""落抽检批次 + 人工裁决到 _comment_gate.jsonl。**不改写任何节点**。
|
|
186
|
+
|
|
187
|
+
权限**自持在模块内**(与 refine 同档):apply 虽只落留痕,但它决定后续是否放行
|
|
188
|
+
**扩批**,故按管理面处理。放在此处而非分发层,是为避免「分发面漏挂一道闸」
|
|
189
|
+
这类易失同步的权限缺口。
|
|
190
|
+
"""
|
|
191
|
+
cg = refine._as_cg(x)
|
|
192
|
+
_principal = getattr(cg, "principal", None)
|
|
193
|
+
if _principal is not None:
|
|
194
|
+
_principal.require_admin("maintain_comment_gate")
|
|
195
|
+
p = plan(cg, ids=ids, n=n, seed=seed)
|
|
196
|
+
batch = batch or time.strftime("%Y%m%d-%H%M%S")
|
|
197
|
+
stats = _stats(verdicts)
|
|
198
|
+
rec = {"t": time.time(), "action": "comment_gate", "batch": batch, "actor": actor,
|
|
199
|
+
"seed": p["seed"], "requested": p["requested"], "pool": p["pool"],
|
|
200
|
+
"sampled": p["sampled"], "sample": p["sample"], "sample_sha": p["sample_sha"],
|
|
201
|
+
"sample_adequacy": p["sample_adequacy"], "verdicts": list(verdicts or []),
|
|
202
|
+
"gate": stats, "note": note}
|
|
203
|
+
os.makedirs(cg.root, exist_ok=True)
|
|
204
|
+
with open(_log_path(cg), "a", encoding="utf-8") as f:
|
|
205
|
+
f.write(json.dumps(rec, ensure_ascii=False) + chr(10))
|
|
206
|
+
return {"ok": True, "action": "comment_gate", "op": "maintain", "batch": batch,
|
|
207
|
+
"root": cg.root, "sampled": p["sampled"], "gate": stats, "log": LOG_NAME,
|
|
208
|
+
"note": ("抽检留痕已落盘(未改任何节点);" +
|
|
209
|
+
("闸门放行扩批" if stats["expand_allowed"] else
|
|
210
|
+
"闸门未放行:" + stats["reason"]))}
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
# 生效条件:x 传入后经 refine._as_cg 得到 cg,读取 _log_path(cg) 且仅当 os.path.exists 为真时逐行解析(空行跳过、json.loads 抛 ValueError 的行跳过),batch 为真时仅保留 batch 字段匹配的记录;recs 为空时返回 expand_allowed=False、reason="no_batch",否则取 recs[-1] 的 verdicts 经 _stats 复算并返回。
|
|
214
|
+
def gate(x, batch=None) -> dict:
|
|
215
|
+
"""扩批闸门:读留痕复算通过率(不写盘)。"""
|
|
216
|
+
cg = refine._as_cg(x)
|
|
217
|
+
recs = []
|
|
218
|
+
path = _log_path(cg)
|
|
219
|
+
if os.path.exists(path):
|
|
220
|
+
with open(path, encoding="utf-8", errors="replace") as f:
|
|
221
|
+
for line in f:
|
|
222
|
+
line = line.strip()
|
|
223
|
+
if not line:
|
|
224
|
+
continue
|
|
225
|
+
try:
|
|
226
|
+
recs.append(json.loads(line))
|
|
227
|
+
except ValueError:
|
|
228
|
+
continue
|
|
229
|
+
if batch:
|
|
230
|
+
recs = [r for r in recs if r.get("batch") == batch]
|
|
231
|
+
if not recs:
|
|
232
|
+
return {"ok": True, "action": "comment_gate_gate", "op": "maintain",
|
|
233
|
+
"root": cg.root, "batch": batch, "batches": 0,
|
|
234
|
+
"expand_allowed": False, "reason": "no_batch"}
|
|
235
|
+
rec = recs[-1]
|
|
236
|
+
stats = _stats(rec.get("verdicts"))
|
|
237
|
+
return {"ok": True, "action": "comment_gate_gate", "op": "maintain",
|
|
238
|
+
"root": cg.root, "batch": rec.get("batch"),
|
|
239
|
+
"batches": len({r.get("batch") for r in recs}), **stats}
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
# 生效条件:root 传入后调用 codeindex.index_dir 扫描(max_files 假值回落 500,max_items 假值回落 2000),对返回 items 的每条 comments(假值按空列表)逐条先 str(c).lstrip("#").strip() 再判断是否以 "生效条件" 开头,全部不以该串开头的项进入候选并返回含 items/errors/stats/examined/candidates 的字典。
|
|
243
|
+
def candidates_from_sources(root, patterns=None, max_files=None, max_items=None,
|
|
244
|
+
skip_dirs=None):
|
|
245
|
+
"""**源级**候选枚举(不依赖认知图):扫源码树,筛出注释里缺『生效条件』的符号。
|
|
246
|
+
|
|
247
|
+
为什么需要它(2026-09-17 实测):真实库 2934 条 code_ 节点的生效条件 **100% 是旧 render
|
|
248
|
+
的合成值**,故**图内候选池为 0**;而「源码里哪些符号缺条件注释」是**源侧事实**,
|
|
249
|
+
无须先重索引(重索引会让 2934 条同时失去条件、判 BLINDSPOT)。本入口绕开该一次性代价。
|
|
250
|
+
|
|
251
|
+
判据唯一且机械:符号的 **井号注释窗口**(leading + body,见 codeindex)中不存在以
|
|
252
|
+
『生效条件』开头的行;只认井号注释、不认 docstring——落点按 q-0 裁决。
|
|
253
|
+
"""
|
|
254
|
+
items, errors, stats = codeindex.index_dir(
|
|
255
|
+
root, patterns=patterns, max_files=int(max_files or 500),
|
|
256
|
+
max_items=int(max_items or 2000), skip_dirs=skip_dirs)
|
|
257
|
+
cands = []
|
|
258
|
+
for it in items:
|
|
259
|
+
has = any(str(c).lstrip("#").strip().startswith("生效条件")
|
|
260
|
+
for c in (it.get("comments") or []))
|
|
261
|
+
if not has:
|
|
262
|
+
cands.append(it)
|
|
263
|
+
return {"root": root, "items": cands, "errors": errors, "stats": stats,
|
|
264
|
+
"examined": len(items), "candidates": len(cands),
|
|
265
|
+
"note": ("源级枚举:判据=井号注释窗口内无『生效条件』行;"
|
|
266
|
+
"不含图内节点状态,故不受存量渲染影响")}
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
# 生效条件:it 传入后取 it.get("path")(假值按空串)按 "/" 分割首段作为 family(首段为空则 family="."),并返回含 id=codeindex.node_id(it)、name/kind、code_ref(path/lineno/end/lang/precise 各缺省 None)、comments(假值按空列表逐项 str)、以及固定 landing_rule 与 landing_note 的字典。
|
|
270
|
+
def _landing_src(it) -> dict:
|
|
271
|
+
return {"id": codeindex.node_id(it), "name": it.get("name"),
|
|
272
|
+
"kind": it.get("kind"),
|
|
273
|
+
"family": (it.get("path") or "").split("/")[0] or ".",
|
|
274
|
+
"code_ref": {"path": it.get("path"), "lineno": it.get("lineno"),
|
|
275
|
+
"end": it.get("end"), "lang": it.get("lang"),
|
|
276
|
+
"precise": it.get("precise")},
|
|
277
|
+
"comments": [str(c) for c in (it.get("comments") or [])],
|
|
278
|
+
"landing_rule": ("定义行紧邻上方连续井号注释(leading)或定义行紧邻下方、"
|
|
279
|
+
"体首语句之前(body)"),
|
|
280
|
+
"landing_note": "两窗口按源码物理行序合并;靠前者胜出(契约 §三.2)"}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
# 生效条件:root 传入后调用 candidates_from_sources(root, patterns=patterns, skip_dirs=skip_dirs, max_files=max_files, max_items=max_items) 得候选,seed 假值回落 SAMPLE_SEED,n 为 None 时取 SAMPLE_N 否则 int(n)(0 保持 0),按 path 首段(空则 ".")分族与 sha(seed, node_id) 排序后做族间确定性轮转取至多 n 项,返回只读源级工单。
|
|
284
|
+
def plan_sources(root, n=None, seed=None, patterns=None, skip_dirs=None,
|
|
285
|
+
max_files=None, max_items=None) -> dict:
|
|
286
|
+
"""**源级**工单(只读):确定性抽样 + 源码落点;不依赖认知图、不改任何节点。
|
|
287
|
+
|
|
288
|
+
抽样口径:按大域(顶层目录)**确定性轮转**(族内按 sha(seed,id) 排序)。
|
|
289
|
+
刻意**不复制** refine 的浮点最大余数分配——那是第二份实现,会引入漂移;
|
|
290
|
+
源级候选列表是精确的(无「先抽样再过滤」的口径损失),轮转已给出跨族覆盖。
|
|
291
|
+
"""
|
|
292
|
+
seed = seed or SAMPLE_SEED
|
|
293
|
+
n = SAMPLE_N if n is None else int(n)
|
|
294
|
+
got = candidates_from_sources(root, patterns=patterns, skip_dirs=skip_dirs,
|
|
295
|
+
max_files=max_files, max_items=max_items)
|
|
296
|
+
fams = {}
|
|
297
|
+
for it in got["items"]:
|
|
298
|
+
top = (it.get("path") or "").split("/")[0] or "."
|
|
299
|
+
fams.setdefault(top, []).append(it)
|
|
300
|
+
pools = {f: len(v) for f, v in fams.items()}
|
|
301
|
+
names = sorted(fams)
|
|
302
|
+
for f in names:
|
|
303
|
+
fams[f].sort(key=lambda it: refine._sha(seed, codeindex.node_id(it)))
|
|
304
|
+
picked = []
|
|
305
|
+
while len(picked) < n and any(fams[f] for f in names):
|
|
306
|
+
for f in names:
|
|
307
|
+
if fams[f] and len(picked) < n:
|
|
308
|
+
picked.append(fams[f].pop(0))
|
|
309
|
+
work = [_landing_src(it) for it in picked]
|
|
310
|
+
return {"root": root, "dry_run": True, "readonly": True, "mode": "source_level",
|
|
311
|
+
"action": "comment_gate_sources", "op": "maintain",
|
|
312
|
+
"seed": seed, "requested": n, "examined": got["examined"],
|
|
313
|
+
"candidates": got["candidates"], "sampled": len(work),
|
|
314
|
+
"families": len(pools), "strata": pools,
|
|
315
|
+
"items": work, "worklist": work, "spec": SPEC,
|
|
316
|
+
"scan_errors": list(got["errors"])[:10], "scan_stats": got["stats"],
|
|
317
|
+
"gate_rule": SPEC["gate"],
|
|
318
|
+
"note": ("源级工单(只读):不依赖认知图、不改任何节点;"
|
|
319
|
+
"抽样为按大域的确定性轮转。")}
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
# 生效条件:x 与 action 传入后,action=="comment_gate" 时若 kw.get("apply") 为真则转 apply(x, ids,n,seed,verdicts,actor,note,batch),否则转 plan(x, ids,n,seed);action=="comment_gate_verdict" 时转 gate(x, batch);action 为 "comment_gate_sources" 或 "comment_gate_source_plan" 时以 root=kw.get("root") or getattr(x,"root",None) or str(x) 转 plan_sources(...);其余 action 抛 ValueError。
|
|
323
|
+
def run(x, action, **kw) -> dict:
|
|
324
|
+
"""maintain op 分派入口(与 backfill.run 同形,便于 mcp_server 侧并列分派)。"""
|
|
325
|
+
if action == "comment_gate":
|
|
326
|
+
if kw.get("apply"):
|
|
327
|
+
return apply(x, ids=kw.get("ids"), n=kw.get("n"), seed=kw.get("seed"),
|
|
328
|
+
verdicts=kw.get("verdicts"), actor=kw.get("actor"),
|
|
329
|
+
note=kw.get("note"), batch=kw.get("batch"))
|
|
330
|
+
return plan(x, ids=kw.get("ids"), n=kw.get("n"), seed=kw.get("seed"))
|
|
331
|
+
if action == "comment_gate_verdict":
|
|
332
|
+
return gate(x, batch=kw.get("batch"))
|
|
333
|
+
if action in ("comment_gate_sources", "comment_gate_source_plan"):
|
|
334
|
+
root = kw.get("root") or getattr(x, "root", None) or str(x)
|
|
335
|
+
return plan_sources(root, n=kw.get("n"), seed=kw.get("seed"),
|
|
336
|
+
patterns=kw.get("patterns"), skip_dirs=kw.get("skip_dirs"))
|
|
337
|
+
raise ValueError("未知 comment_gate action:%s(允许 comment_gate / "
|
|
338
|
+
"comment_gate_verdict)" % action)
|