@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,485 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""M4 落库治理自测(确定性部分):rule 驱动靶子 + 来源链 + 五纪律 + CLI。
|
|
3
|
+
|
|
4
|
+
真源:docs/记忆评审系统_立项设计与施工交接_20260915.md §3 第 4 级 + §6 验收 + §7 负面清单。
|
|
5
|
+
|
|
6
|
+
纪律(同 test_mr_m1/m2/m3):
|
|
7
|
+
· **自备数据源**——合成节点 + tempfile 合成库,零依赖真源库(外部 clone 全绿)。
|
|
8
|
+
· **零删除实锤**——全相位跑完节点集合只增不减(M4 只写 frontmatter 一个字段)。
|
|
9
|
+
· **不猜**——无来源记 `unfillable` + 原因分布;域外值**停止降级**;工作角色不被推断。
|
|
10
|
+
· **可回滚**——写入值即回滚锚点;当前值被人工改动 → `conflict` 不覆盖。
|
|
11
|
+
|
|
12
|
+
覆盖:A 靶子定位(rule 驱动,引擎不写死) B 取值推导(只搬运已声明证据)
|
|
13
|
+
C 预演(零写入) D 执行(写前重查 / 留痕 / 幂等 / 零删除)
|
|
14
|
+
E 回滚(还原 / 删键 / 冲突) F CLI(fail-closed)
|
|
15
|
+
G 对照口径(复用 conformance,不复刻判据)
|
|
16
|
+
运行:python -m md_cg.test_mr_m4
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import contextlib
|
|
21
|
+
import hashlib
|
|
22
|
+
import io
|
|
23
|
+
import json
|
|
24
|
+
import os
|
|
25
|
+
import shutil
|
|
26
|
+
import sys
|
|
27
|
+
import tempfile
|
|
28
|
+
|
|
29
|
+
from . import conformance as CF
|
|
30
|
+
from . import crypto
|
|
31
|
+
from . import nodefile as NF
|
|
32
|
+
from .mdcos import MdCGOS
|
|
33
|
+
from .mreview import govern as GV
|
|
34
|
+
|
|
35
|
+
PASS = FAIL = SKIP = 0
|
|
36
|
+
FAILS = []
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def ok(cond, label):
|
|
40
|
+
global PASS, FAIL
|
|
41
|
+
if cond:
|
|
42
|
+
PASS += 1
|
|
43
|
+
else:
|
|
44
|
+
FAIL += 1
|
|
45
|
+
FAILS.append(label)
|
|
46
|
+
print(" FAIL %s" % label)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def skip(label):
|
|
50
|
+
global SKIP
|
|
51
|
+
SKIP += 1
|
|
52
|
+
print(" SKIP %s" % label)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# ---------------------------- 合成库 ----------------------------
|
|
56
|
+
|
|
57
|
+
BODY = ("# 功能名:示例能力\n# 生效条件:载体/位置:本地仓;时间:全时窗(任意时刻成立);"
|
|
58
|
+
"方法:test;约束:无\n# 子功能:a/b\n# 执行:python -m md_cg.demo\n"
|
|
59
|
+
"# 验证方式:test\n# 不适用条件:无\n正文。")
|
|
60
|
+
LOCKED = crypto.ENC_PREFIX + "QUJDREVG" + crypto.ENC_SUFFIX
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def mkroot(root, nodes):
|
|
64
|
+
"""合成认知图根:`_index.json` + 节点盘文件(与 test_mr_m3 同范式)。"""
|
|
65
|
+
os.makedirs(root, exist_ok=True)
|
|
66
|
+
idx = {}
|
|
67
|
+
for nid, spec in nodes.items():
|
|
68
|
+
fm = dict(spec.get("fm") or {})
|
|
69
|
+
fm.setdefault("id", nid)
|
|
70
|
+
content = spec.get("content")
|
|
71
|
+
content = BODY if content is None else content
|
|
72
|
+
rel = spec.get("path") or ("%s/%s.md" % (spec.get("layer") or "knowledge", nid))
|
|
73
|
+
p = os.path.join(root, rel)
|
|
74
|
+
os.makedirs(os.path.dirname(p), exist_ok=True)
|
|
75
|
+
with open(p, "w", encoding="utf-8") as f:
|
|
76
|
+
f.write(NF.dumps(fm, content))
|
|
77
|
+
meta = dict(spec.get("meta") or {})
|
|
78
|
+
meta.update({"id": nid, "path": rel,
|
|
79
|
+
"layer": spec.get("layer") or "knowledge"})
|
|
80
|
+
if "role" in fm:
|
|
81
|
+
meta["role"] = fm["role"]
|
|
82
|
+
idx[nid] = meta
|
|
83
|
+
with open(os.path.join(root, CF.INDEX_FILE), "w", encoding="utf-8") as f:
|
|
84
|
+
json.dump({"nodes": idx}, f, ensure_ascii=False)
|
|
85
|
+
return root
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def snapshot(root):
|
|
89
|
+
out = {}
|
|
90
|
+
for dp, _dns, fns in os.walk(root):
|
|
91
|
+
for fn in fns:
|
|
92
|
+
p = os.path.join(dp, fn)
|
|
93
|
+
with open(p, "rb") as f:
|
|
94
|
+
out[os.path.relpath(p, root)] = hashlib.md5(f.read()).hexdigest()
|
|
95
|
+
return out
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def disk_role(root, nid, layer="knowledge"):
|
|
99
|
+
p = os.path.join(root, layer, "%s.md" % nid)
|
|
100
|
+
with open(p, encoding="utf-8") as f:
|
|
101
|
+
fm, _c = NF.loads(f.read())
|
|
102
|
+
return fm
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def base_nodes():
|
|
106
|
+
"""六类靶面各一条:成文标签 / writer / 无声明 / 已有值 / 域外 / 密文 + 域外层。"""
|
|
107
|
+
return {
|
|
108
|
+
"k1": {"fm": {"tags": ["role:knowledge", "主题"]}},
|
|
109
|
+
"k2": {"fm": {"writer": "dsh-memory"}},
|
|
110
|
+
"k3": {"fm": {"tags": ["无声明"]}},
|
|
111
|
+
"k4": {"fm": {"role": "user", "tags": ["role:knowledge"]}},
|
|
112
|
+
"k5": {"fm": {"tags": ["role:工具"]}},
|
|
113
|
+
"k6": {"content": LOCKED},
|
|
114
|
+
"c1": {"fm": {"tags": ["role:knowledge"]}, "layer": "contextual"},
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def rm(path):
|
|
119
|
+
shutil.rmtree(path, ignore_errors=True)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# ---------------------------- A 组:靶子定位(rule 驱动)----------------------------
|
|
123
|
+
|
|
124
|
+
def phase_a(tmp):
|
|
125
|
+
print("[A] 靶子定位(规则库是靶子唯一真源,引擎不写死)")
|
|
126
|
+
rule = GV.role_rule()
|
|
127
|
+
ok(rule["rule_id"] == "R-ROLE-MISSING" and rule["field"] == "role",
|
|
128
|
+
"A1 从真规则库取到靶规则(field=%s)" % rule["field"])
|
|
129
|
+
ok(rule["layers"] == ["knowledge"], "A2 作用域取自 matcher.layer(%s)" % rule["layers"])
|
|
130
|
+
ok(rule["field"] == "role",
|
|
131
|
+
"A3 字段名取自 mechanical[%s].field(不写死)" % GV.CHECK_FIELD_ABSENT)
|
|
132
|
+
|
|
133
|
+
# 规则库可替换:换成临时规则库(field=其他字段)→ 引擎随之改靶,零代码改动
|
|
134
|
+
d = os.path.join(tmp, "rules")
|
|
135
|
+
os.makedirs(d, exist_ok=True)
|
|
136
|
+
with open(os.path.join(d, "x.json"), "w", encoding="utf-8") as f:
|
|
137
|
+
json.dump({"rules": [{"id": "R-ROLE-MISSING", "title": "改靶", "severity": "INFO",
|
|
138
|
+
"matcher": {"layer": ["contextual"]},
|
|
139
|
+
"mechanical": [{"check": "field_absent", "field": "owner"}]}]}, f)
|
|
140
|
+
r2 = GV.role_rule(rules_dir=d)
|
|
141
|
+
ok(r2["field"] == "owner" and r2["layers"] == ["contextual"],
|
|
142
|
+
"A4 改数据即改靶(field=%s layers=%s),引擎零改动" % (r2["field"], r2["layers"]))
|
|
143
|
+
|
|
144
|
+
for bad, label in (({"rules": []}, "A5 规则库无该规则 → ValueError(靶子失效必须红灯)"),
|
|
145
|
+
({"rules": [{"id": "R-ROLE-MISSING", "severity": "INFO",
|
|
146
|
+
"mechanical": [{"check": "field_absent", "field": "role"}]}]},
|
|
147
|
+
"A6 规则缺 matcher.layer → ValueError"),
|
|
148
|
+
({"rules": [{"id": "R-ROLE-MISSING", "severity": "INFO",
|
|
149
|
+
"matcher": {"layer": ["knowledge"]}, "mechanical": []}]},
|
|
150
|
+
"A7 规则缺 field_absent.field → ValueError")):
|
|
151
|
+
try:
|
|
152
|
+
GV.role_rule(rules=bad)
|
|
153
|
+
ok(False, label + "(未抛错)")
|
|
154
|
+
except ValueError:
|
|
155
|
+
ok(True, label)
|
|
156
|
+
|
|
157
|
+
root = mkroot(os.path.join(tmp, "a"), base_nodes())
|
|
158
|
+
try:
|
|
159
|
+
GV.role_plan(root, layer="contextual")
|
|
160
|
+
ok(False, "A8 跨层收窄应抛错(绝不跨层套用)")
|
|
161
|
+
except ValueError:
|
|
162
|
+
ok(True, "A8 跨层收窄抛错(绝不跨层套用)")
|
|
163
|
+
rep = GV.role_plan(root, layer="knowledge")
|
|
164
|
+
ok(rep["rule_layers"] == ["knowledge"] and rep["skipped_out_of_scope"] == 1,
|
|
165
|
+
"A9 层内收窄不抛错,域外条数如实上报(%d)" % rep["skipped_out_of_scope"])
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# ---------------------------- B 组:取值推导 ----------------------------
|
|
169
|
+
|
|
170
|
+
def phase_b(tmp):
|
|
171
|
+
print("[B] 取值推导(只搬运已声明证据,绝不编造)")
|
|
172
|
+
root = mkroot(os.path.join(tmp, "b"), base_nodes())
|
|
173
|
+
|
|
174
|
+
# 默认档(tags + map),map 需显式补表(WRITER_ROLE_MAP 故意为空)
|
|
175
|
+
p = GV.role_plan(root)
|
|
176
|
+
ok(GV.SOURCE_LAYER not in p["sources"],
|
|
177
|
+
"B1 默认档不含 layer_default(%s)——不得用常量填满指标" % (p["sources"],))
|
|
178
|
+
ok(p["by_source"] == {"tags": 1}, "B2 默认档只认成文标签(%s)" % p["by_source"])
|
|
179
|
+
ok(p["unfillable_by_reason"].get(GV.REASON_NO_SOURCE) == 1,
|
|
180
|
+
"B3 无任何声明 → no_source_declared(不猜)")
|
|
181
|
+
ok(p["unfillable_by_reason"].get(GV.REASON_WRITER_NO_MAP + ":dsh-memory") == 1,
|
|
182
|
+
"B4 writer 有值但映射表空 → writer_no_mapping:<writer>(待终裁补表)")
|
|
183
|
+
ok(p["unfillable_by_reason"].get(GV.REASON_TAG_OOD + ":工具") == 1,
|
|
184
|
+
"B5 域外标签值如实上报(%s)" % p["unfillable_by_reason"])
|
|
185
|
+
ok(p["skipped_present"] == 1, "B6 已有 role 值者不重复回填")
|
|
186
|
+
ok(p["skipped_locked"] == 1, "B7 密文节点跳过(绝不解密回写)")
|
|
187
|
+
|
|
188
|
+
# ① tags 成文声明优先且直取
|
|
189
|
+
p2 = GV.role_plan(root, ids=["k1"], sources=("tags", "map", "layer_default"))
|
|
190
|
+
it = p2["items"][0]
|
|
191
|
+
ok(it["role"] == "knowledge" and it["source"] == "tags",
|
|
192
|
+
"B8 tags 声明直取(%s / %s)" % (it["role"], it["source"]))
|
|
193
|
+
ok(it["basis"] == GV.BASIS_TAG, "B9 依据落在 basis(可审计,%s)" % it["basis"])
|
|
194
|
+
|
|
195
|
+
# ② map 档:显式补表才生效
|
|
196
|
+
p3 = GV.role_plan(root, role_map={"dsh-memory": "knowledge"})
|
|
197
|
+
ok(p3["by_source"] == {"tags": 1, "map": 1},
|
|
198
|
+
"B10 映射表补声明后 map 档生效(%s)" % p3["by_source"])
|
|
199
|
+
ok(p3["unfillable_by_reason"].get(GV.REASON_WRITER_NO_MAP + ":dsh-memory") is None,
|
|
200
|
+
"B11 补表后原 writer_no_mapping 消失(原因分布随声明变化)")
|
|
201
|
+
|
|
202
|
+
# ② OOD:映射表写域外值 → 停止降级
|
|
203
|
+
p4 = GV.role_plan(root, role_map={"dsh-memory": "不存在的角色"})
|
|
204
|
+
ok(p4["unfillable_by_reason"].get(GV.REASON_MAP_OOD + ":不存在的角色") == 1,
|
|
205
|
+
"B13 映射表域外值 → map_role_out_of_domain(%s)" % p4["unfillable_by_reason"])
|
|
206
|
+
|
|
207
|
+
# ② 工作角色:映射表写 tool-output → 拒绝(不许把知识节点摘出默认召回)
|
|
208
|
+
p5 = GV.role_plan(root, role_map={"dsh-memory": "tool-output"})
|
|
209
|
+
ok(p5["unfillable_by_reason"].get(GV.REASON_MAP_WORK + ":tool-output") == 1,
|
|
210
|
+
"B14 映射表推成工作角色 → 拒绝(%s)" % p5["unfillable_by_reason"])
|
|
211
|
+
ok(p5["targeted"] == 1 and p5["by_source"] == {"tags": 1},
|
|
212
|
+
"B15 工作角色被拒后**不**回退到其它档(拒绝即终态)")
|
|
213
|
+
|
|
214
|
+
# ③ layer_default:显式开启才可用
|
|
215
|
+
p6 = GV.role_plan(root, sources=("tags", "map", "layer_default"))
|
|
216
|
+
ok(p6["by_source"].get("layer_default") == 2,
|
|
217
|
+
"B16 layer_default 档显式开启后生效(%s)" % p6["by_source"])
|
|
218
|
+
ok(p6["targeted"] > p["targeted"], "B17 开启后靶面扩大(%d → %d)"
|
|
219
|
+
% (p["targeted"], p6["targeted"]))
|
|
220
|
+
|
|
221
|
+
# tags 域外值不因开启更多档而降级
|
|
222
|
+
p7 = GV.role_plan(root, ids=["k5"], sources=("tags", "map", "layer_default"))
|
|
223
|
+
ok(p7["targeted"] == 0 and p7["unfillable_by_reason"].get(GV.REASON_TAG_OOD + ":工具") == 1,
|
|
224
|
+
"B18 标签域外值在最强档下仍不降级(显式声明 ≠ 无声明)")
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
# ---------------------------- C 组:预演(零写入)----------------------------
|
|
228
|
+
|
|
229
|
+
def phase_c(tmp):
|
|
230
|
+
print("[C] 预演(零写入)")
|
|
231
|
+
root = mkroot(os.path.join(tmp, "c"), base_nodes())
|
|
232
|
+
GV.role_plan(root) # 预热(首建实例可能补索引)
|
|
233
|
+
before = snapshot(root)
|
|
234
|
+
GV.role_plan(root, sources=GV.ALL_SOURCES)
|
|
235
|
+
GV.role_stats(root)
|
|
236
|
+
GV.history(root)
|
|
237
|
+
ok(snapshot(root) == before, "C1 预演 / 统计 / 留痕读全程零写入(指纹不变)")
|
|
238
|
+
|
|
239
|
+
p = GV.role_plan(root, sources=GV.ALL_SOURCES)
|
|
240
|
+
ok(p["dry_run"] is True and p["action"] == GV.ACTION_ROLE, "C2 预演自报只读")
|
|
241
|
+
ok(p["nodes_scanned"] == 6 and p["skipped_out_of_scope"] == 1,
|
|
242
|
+
"C3 扫描面=层内 6 / 域外 1(%d/%d)" % (p["nodes_scanned"], p["skipped_out_of_scope"]))
|
|
243
|
+
ok(p["targeted"] == 3, "C4 最强档靶面 3 条(%d)" % p["targeted"])
|
|
244
|
+
|
|
245
|
+
p2 = GV.role_plan(root, sources=GV.ALL_SOURCES, limit=2)
|
|
246
|
+
ok(len(p2["items"]) == 2 and p2["targeted"] == 3,
|
|
247
|
+
"C5 limit 只截清单不动靶面(items=%d targeted=%d)" % (len(p2["items"]), p2["targeted"]))
|
|
248
|
+
|
|
249
|
+
p3 = GV.role_plan(root, ids=["k3"])
|
|
250
|
+
ok(p3["nodes_scanned"] == 1 and p3["skipped_out_of_scope"] == 0,
|
|
251
|
+
"C6 ids 收窄同时收窄扫描面与域外计数")
|
|
252
|
+
p4 = GV.role_plan(root, prefix="k1")
|
|
253
|
+
ok(p4["nodes_scanned"] == 1, "C7 prefix 收窄(%d)" % p4["nodes_scanned"])
|
|
254
|
+
p5 = GV.role_plan(root, sources=GV.ALL_SOURCES, sample=2)
|
|
255
|
+
ok(len(p5.get("sample") or []) == 2, "C8 sample 抽样(%s)" % p5.get("sample"))
|
|
256
|
+
ok(p5["planned_ids"] == [i["id"] for i in p5["items"]],
|
|
257
|
+
"C9 planned_ids 与清单同源(%s)" % p5["planned_ids"])
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
# ---------------------------- D 组:执行 ----------------------------
|
|
261
|
+
|
|
262
|
+
def write_node(root, nid, fm, layer="knowledge", content=None):
|
|
263
|
+
p = os.path.join(root, layer, "%s.md" % nid)
|
|
264
|
+
with open(p, encoding="utf-8") as f:
|
|
265
|
+
_fm, c = NF.loads(f.read())
|
|
266
|
+
with open(p, "w", encoding="utf-8") as f:
|
|
267
|
+
f.write(NF.dumps(fm, c if content is None else content))
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def idx_role(root, nid):
|
|
271
|
+
with open(os.path.join(root, CF.INDEX_FILE), encoding="utf-8") as f:
|
|
272
|
+
return (json.load(f)["nodes"].get(nid) or {}).get("role")
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def phase_d(tmp):
|
|
276
|
+
print("[D] 执行(写前重查 / 留痕 / 幂等 / 零删除)")
|
|
277
|
+
root = mkroot(os.path.join(tmp, "d"), base_nodes())
|
|
278
|
+
files0 = set(snapshot(root))
|
|
279
|
+
c1_0 = snapshot(root).get("contextual/c1.md")
|
|
280
|
+
|
|
281
|
+
rep = GV.role_apply(root, role_map={"dsh-memory": "knowledge"},
|
|
282
|
+
batch="b1", actor="tester")
|
|
283
|
+
ok(rep["written"] == 2 and rep["by_source"] == {"tags": 1, "map": 1},
|
|
284
|
+
"D1 写入 2 条(%s)" % rep["by_source"])
|
|
285
|
+
ok(disk_role(root, "k1")["role"] == "knowledge", "D2 tags 档写盘生效")
|
|
286
|
+
ok(disk_role(root, "k2")["role"] == "knowledge", "D3 map 档写盘生效")
|
|
287
|
+
ok("role" not in disk_role(root, "k3"), "D4 无来源者不写(宁可缺失不猜)")
|
|
288
|
+
ok("role" not in disk_role(root, "k6"), "D5 密文节点不写")
|
|
289
|
+
ok(idx_role(root, "k1") == "knowledge",
|
|
290
|
+
"D6 role 进索引(覆盖率判据据此可算)")
|
|
291
|
+
ok(idx_role(root, "k3") is None, "D7 未回填者索引也无值(盘/索引一致)")
|
|
292
|
+
|
|
293
|
+
h = GV.history(root, action=GV.ACTION_ROLE)
|
|
294
|
+
rec = [r for r in h["records"] if r["node"] == "k1"][0]
|
|
295
|
+
ok(all(k in rec for k in ("batch", "actor", "write_id", "entry_id", "value",
|
|
296
|
+
"source", "basis", "fm_before", "layer", "rule_id")),
|
|
297
|
+
"D8 留痕字段完整(回滚凭据齐备)")
|
|
298
|
+
ok(rec["fm_before"] == {"role": None, "had_key": False},
|
|
299
|
+
"D9 留痕记下写前态(原本无键)")
|
|
300
|
+
ok(bool(rec["write_id"]) and len(rec["entry_id"]) == 12,
|
|
301
|
+
"D10 write_id / entry_id 齐备(回滚去重与对账凭据)")
|
|
302
|
+
|
|
303
|
+
rep2 = GV.role_apply(root, role_map={"dsh-memory": "knowledge"}, batch="b1")
|
|
304
|
+
ok(rep2["written"] == 0 and rep2["skipped_drift"] == 0,
|
|
305
|
+
"D11 幂等:重跑零写入(已有值在预演面即被 present 拦截)")
|
|
306
|
+
|
|
307
|
+
orig = GV.role_plan
|
|
308
|
+
|
|
309
|
+
def patched(x, **kw):
|
|
310
|
+
r = orig(x, **kw)
|
|
311
|
+
for it in r["items"]: # 预演→执行之间模拟他人改动
|
|
312
|
+
if it["id"] == "k3":
|
|
313
|
+
fm = disk_role(root, "k3")
|
|
314
|
+
fm["role"] = "assistant"
|
|
315
|
+
write_node(root, "k3", fm)
|
|
316
|
+
return r
|
|
317
|
+
|
|
318
|
+
GV.role_plan = patched
|
|
319
|
+
try:
|
|
320
|
+
rep3 = GV.role_apply(root, ids=["k3"], sources=GV.ALL_SOURCES, batch="b2")
|
|
321
|
+
finally:
|
|
322
|
+
GV.role_plan = orig
|
|
323
|
+
ok(rep3["written"] == 0 and rep3["skipped_drift"] == 1,
|
|
324
|
+
"D12 写前重查:预演后被人改动 → 不覆盖(written=%d drift=%d)"
|
|
325
|
+
% (rep3["written"], rep3["skipped_drift"]))
|
|
326
|
+
ok(disk_role(root, "k3")["role"] == "assistant", "D13 漂移节点保持他人值")
|
|
327
|
+
|
|
328
|
+
ok(set(snapshot(root)) >= files0 and snapshot(root).get("contextual/c1.md") == c1_0,
|
|
329
|
+
"D14 零删除:文件集合只增不减、域外节点零触碰")
|
|
330
|
+
with open(os.path.join(root, CF.INDEX_FILE), encoding="utf-8") as f:
|
|
331
|
+
ok(len(json.load(f)["nodes"]) == 7, "D15 治理后节点总数不变(7)")
|
|
332
|
+
|
|
333
|
+
r2 = mkroot(os.path.join(tmp, "d2"), {
|
|
334
|
+
"a1": {"fm": {"tags": ["role:user"]}},
|
|
335
|
+
"a2": {"fm": {"tags": ["role:knowledge"]}},
|
|
336
|
+
"a3": {"fm": {"tags": ["role:developer"]}}})
|
|
337
|
+
p = GV.role_plan(r2)
|
|
338
|
+
eid = [i for i in p["items"] if i["id"] == "a2"][0]["entry_id"]
|
|
339
|
+
rep4 = GV.role_apply(r2, entry_ids=[eid], batch="b3")
|
|
340
|
+
ok(rep4["written"] == 1 and disk_role(r2, "a2")["role"] == "knowledge",
|
|
341
|
+
"D16 entry_ids 工单式精确执行(只写 1 条)")
|
|
342
|
+
ok("role" not in disk_role(r2, "a1") and "role" not in disk_role(r2, "a3"),
|
|
343
|
+
"D17 工单外节点零触碰")
|
|
344
|
+
ok(rep4["plan_remaining"] == 2, "D18 余量如实上报(%d)" % rep4["plan_remaining"])
|
|
345
|
+
ok(rep4["entry_ids"] == [eid], "D19 留痕回执带 entry_id(可对账)")
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
# ---------------------------- E 组:回滚 ----------------------------
|
|
349
|
+
|
|
350
|
+
def phase_e(tmp):
|
|
351
|
+
print("[E] 回滚(还原 / 删键 / 冲突)")
|
|
352
|
+
root = mkroot(os.path.join(tmp, "e"), {
|
|
353
|
+
"a1": {"fm": {"tags": ["role:user"]}},
|
|
354
|
+
"a2": {"fm": {"tags": ["role:knowledge"], "role": ""}},
|
|
355
|
+
"a3": {"fm": {"tags": ["role:developer"]}}})
|
|
356
|
+
had = disk_role(root, "a2")
|
|
357
|
+
ok("role" in had and GV._blank(had.get("role")),
|
|
358
|
+
"E1 空串 role:键在值空 → 视为缺失(键存在性也要还原,%r)" % had.get("role"))
|
|
359
|
+
p0 = GV.role_plan(root)
|
|
360
|
+
ok(p0["targeted"] == 3 and p0["skipped_present"] == 0,
|
|
361
|
+
"E2 空串节点仍入靶面(targeted=%d)" % p0["targeted"])
|
|
362
|
+
base = GV.role_stats(root)["role_ratio_kn"]
|
|
363
|
+
|
|
364
|
+
rep = GV.role_apply(root, batch="e1", actor="t")
|
|
365
|
+
ok(rep["written"] == 3, "E3 三条写入(%d)" % rep["written"])
|
|
366
|
+
ratios_after = GV.role_stats(root)["role_ratio_kn"]
|
|
367
|
+
ok(ratios_after > base, "E4 覆盖率上升(%.4f → %.4f)" % (base, ratios_after))
|
|
368
|
+
ok(GV.role_stats(root)["by_value"] == {"user": 1, "knowledge": 1, "developer": 1},
|
|
369
|
+
"E5 逐值分布正确(%s)" % GV.role_stats(root)["by_value"])
|
|
370
|
+
|
|
371
|
+
fm = disk_role(root, "a1") # 人工覆盖 → 回滚必须让路
|
|
372
|
+
fm["role"] = "assistant"
|
|
373
|
+
write_node(root, "a1", fm)
|
|
374
|
+
rb = GV.role_rollback(root, batch="e1", actor="t")
|
|
375
|
+
ok(rb["reverted"] == 2 and rb["conflict"] == 1,
|
|
376
|
+
"E6 人工改动者计 conflict 不覆盖(reverted=%d conflict=%d)"
|
|
377
|
+
% (rb["reverted"], rb["conflict"]))
|
|
378
|
+
ok(disk_role(root, "a1")["role"] == "assistant", "E7 冲突节点保持人工值")
|
|
379
|
+
ok("role" not in disk_role(root, "a3"), "E8 原本无键 → 删键还原(不写空串)")
|
|
380
|
+
ok("role" in disk_role(root, "a2") and GV._blank(disk_role(root, "a2").get("role")),
|
|
381
|
+
"E9 原本空值 → 还原空值且键仍在(%r)" % disk_role(root, "a2").get("role"))
|
|
382
|
+
ok(idx_role(root, "a3") is None, "E10 索引随回滚同步(role 清空)")
|
|
383
|
+
|
|
384
|
+
rb2 = GV.role_rollback(root, batch="e1", actor="t")
|
|
385
|
+
ok(rb2["reverted"] == 0 and rb2["skipped_done"] == 2 and rb2["conflict"] == 1,
|
|
386
|
+
"E11 重复回滚凭 write_id 去重(skipped_done=%d)" % rb2["skipped_done"])
|
|
387
|
+
ok(GV.role_stats(root)["by_value"] == {"assistant": 1},
|
|
388
|
+
"E12 回滚后仅剩人工值(%s)" % GV.role_stats(root)["by_value"])
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
# ---------------------------- F 组:CLI(fail-closed)----------------------------
|
|
392
|
+
|
|
393
|
+
def run_cli(argv):
|
|
394
|
+
out, err = io.StringIO(), io.StringIO()
|
|
395
|
+
with contextlib.redirect_stdout(out), contextlib.redirect_stderr(err):
|
|
396
|
+
rc = GV.main(argv)
|
|
397
|
+
return rc, out.getvalue(), err.getvalue()
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def phase_f(tmp):
|
|
401
|
+
print("[F] CLI(fail-closed)")
|
|
402
|
+
root = mkroot(os.path.join(tmp, "f"), base_nodes())
|
|
403
|
+
env_bak = os.environ.pop("MDCG_ROOT", None)
|
|
404
|
+
try:
|
|
405
|
+
ok(run_cli(["plan", "--root", root])[0] == 0, "F1 plan 退出码 0")
|
|
406
|
+
ok(run_cli(["plan"])[0] == 2, "F2 无 root → 2(fail-closed)")
|
|
407
|
+
ok(run_cli([])[0] == 2, "F3 无子命令 → 2(print_help)")
|
|
408
|
+
ok(run_cli(["apply", "--root", root])[0] == 2,
|
|
409
|
+
"F4 apply 无 --yes → 2(写盘须显式确认)")
|
|
410
|
+
ok(run_cli(["rollback", "--root", root])[0] == 2,
|
|
411
|
+
"F5 rollback 无范围 → 2(防全量误回滚)")
|
|
412
|
+
ok(run_cli(["plan", "--root", root, "--sources", "tags,bogus"])[0] == 2,
|
|
413
|
+
"F6 来源档域外 → 2(不静默降级)")
|
|
414
|
+
ok(run_cli(["plan", "--root", root, "--layer", "contextual"])[0] == 2,
|
|
415
|
+
"F7 跨层收窄 → 2(异常不得裸奔)")
|
|
416
|
+
|
|
417
|
+
rc, out, err = run_cli(["apply", "--root", root, "--yes", "--batch", "cli1",
|
|
418
|
+
"--sources", "tags,map,layer_default"])
|
|
419
|
+
ok(rc == 0 and GV.LAYER_DEFAULT_WARNING[:14] in err,
|
|
420
|
+
"F8 layer_default 开启时 stderr 透出终裁提示")
|
|
421
|
+
ok(disk_role(root, "k3")["role"] == "knowledge", "F9 CLI apply 生效")
|
|
422
|
+
ok(GV.history(root, batch="cli1")["total"] == 3,
|
|
423
|
+
"F10 CLI 留痕按批次可查(%d)" % GV.history(root, batch="cli1")["total"])
|
|
424
|
+
|
|
425
|
+
rc, out, _e = run_cli(["plan", "--root", root, "--ids", "k1", "--json"])
|
|
426
|
+
ok(rc == 0 and json.loads(out)["nodes_scanned"] == 1,
|
|
427
|
+
"F11 plan --json 可机读(M4 报告引用面)")
|
|
428
|
+
rc, out, _e = run_cli(["history", "--root", root, "--json"])
|
|
429
|
+
ok(rc == 0 and json.loads(out)["total"] >= 3, "F12 history --json 可机读")
|
|
430
|
+
rc, out, _e = run_cli(["rollback", "--root", root, "--batch", "cli1"])
|
|
431
|
+
ok(rc == 0 and "还原" in out, "F13 CLI rollback 人读摘要可读(%s)" % out.split("\n")[0])
|
|
432
|
+
ok("role" not in disk_role(root, "k3"), "F14 CLI 回滚生效(键被删除)")
|
|
433
|
+
finally:
|
|
434
|
+
if env_bak is not None:
|
|
435
|
+
os.environ["MDCG_ROOT"] = env_bak
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
# ---------------------------- G 组:对照口径 ----------------------------
|
|
439
|
+
|
|
440
|
+
def phase_g(tmp):
|
|
441
|
+
print("[G] 对照口径(复用 conformance,不复刻判据)")
|
|
442
|
+
root = mkroot(os.path.join(tmp, "g"), base_nodes())
|
|
443
|
+
st = GV.role_stats(root)
|
|
444
|
+
ok(st["threshold"] == float(CF.THRESHOLDS["role_coverage_min"]),
|
|
445
|
+
"G1 阈值直接取自 conformance(%s)" % st["threshold"])
|
|
446
|
+
mine = CF._coverage_metrics(CF.load_index(root)).get("role_ratio_kn")
|
|
447
|
+
ok(st["role_ratio_kn"] == mine, "G2 覆盖率与 conformance 逐位一致(%s)" % mine)
|
|
448
|
+
ok(st["target_met"] is False and st["gap_to_target"] > 0,
|
|
449
|
+
"G3 未达标时如实上报缺口(%.4f)" % st["gap_to_target"])
|
|
450
|
+
|
|
451
|
+
GV.role_apply(root, role_map={"dsh-memory": "knowledge"}, batch="g1")
|
|
452
|
+
st2 = GV.role_stats(root)
|
|
453
|
+
ok(st2["role_ratio_kn"] > st["role_ratio_kn"],
|
|
454
|
+
"G4 治理后覆盖率变化可量化(%.4f → %.4f)"
|
|
455
|
+
% (st["role_ratio_kn"], st2["role_ratio_kn"]))
|
|
456
|
+
ok(st2["by_layer"].get("knowledge") == 6,
|
|
457
|
+
"G5 逐层分布(knowledge=%s)" % st2["by_layer"].get("knowledge"))
|
|
458
|
+
|
|
459
|
+
try:
|
|
460
|
+
GV.run(root, "role_bogus")
|
|
461
|
+
ok(False, "G6 未知 action → ValueError")
|
|
462
|
+
except ValueError:
|
|
463
|
+
ok(True, "G6 未知 action → ValueError(入口防呆)")
|
|
464
|
+
ok(GV.run(root, "role", apply=False)["dry_run"] is True,
|
|
465
|
+
"G7 run(apply=False) 走预演(默认不写)")
|
|
466
|
+
ok(GV.run(root, "role_stats")["action"] == "role_stats", "G8 run 分发到对照")
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
# ---------------------------- 入口 ----------------------------
|
|
470
|
+
|
|
471
|
+
def main():
|
|
472
|
+
tmp = tempfile.mkdtemp(prefix="m4_govern_")
|
|
473
|
+
try:
|
|
474
|
+
for fn in (phase_a, phase_b, phase_c, phase_d, phase_e, phase_f, phase_g):
|
|
475
|
+
fn(tmp)
|
|
476
|
+
finally:
|
|
477
|
+
rm(tmp)
|
|
478
|
+
print("\nPASS %d FAIL %d SKIP %d" % (PASS, FAIL, SKIP))
|
|
479
|
+
for f in FAILS:
|
|
480
|
+
print(" - %s" % f)
|
|
481
|
+
return 1 if FAIL else 0
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
if __name__ == "__main__":
|
|
485
|
+
sys.exit(main())
|
package/md_cg/test_p1.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
"""md 认知图 P1 验收 · 白箱认知架构 9 维度补全
|
|
3
3
|
|
|
4
|
-
覆盖(对照 docs/认知图_MD目录方案_v0.1.md v0.3 待办 + 白箱 5 篇):
|
|
4
|
+
覆盖(对照 docs/mdcg/认知图_MD目录方案_v0.1.md v0.3 待办 + 白箱 5 篇):
|
|
5
5
|
1. MARKS 5 要素 + 验证基底 + 不适用条件
|
|
6
6
|
2. 负记忆目录(rejected/unresolved)
|
|
7
7
|
3. 资格判定四态(ACCEPT/REJECT/DEFER/BLINDSPOT)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""md_cg · 第 11 篇:节点间自动冲突检测(三级决策:情绪 → 反思 → 递归反思)
|
|
3
3
|
|
|
4
4
|
理论出处(本仓原文):
|
|
5
|
-
· 情绪 = 信息差二阶变化 d²D/dt²(`docs/智能的公理化基石.md` §十一)
|
|
5
|
+
· 情绪 = 信息差二阶变化 d²D/dt²(`docs/theory/智能的公理化基石.md` §十一)
|
|
6
6
|
—— L0,独立通道,**不参与信任计算**
|
|
7
7
|
· 反题 = 预测与事实冲突(同文档 :529,条件论七操作)—— L1 条件级冲突检测
|
|
8
8
|
· 递归受深度/节点数/循环/信息增益门槛约束(同文档 :273)—— L2 递归反思
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
"""md_cg · 第 12 篇:独立元认知(观察自身认知的二阶单元)
|
|
3
3
|
|
|
4
4
|
理论出处(本仓原文):
|
|
5
|
-
· 情绪 = 信息差二阶变化 d²D/dt²(`docs/智能的公理化基石.md` §十一,:412-510)
|
|
5
|
+
· 情绪 = 信息差二阶变化 d²D/dt²(`docs/theory/智能的公理化基石.md` §十一,:412-510)
|
|
6
6
|
· 情感 = 信任二阶变化 d²T/dt²(同文档 :469-508)
|
|
7
7
|
· 五大单元:元认知是反思/验证通道的**外部观察者**(同文档 :540-556)
|
|
8
8
|
· 推论三「局部不可知」:盲区即知识(同文档 :277-288)
|
|
9
9
|
· 信任 P_trust / P_gap(同文档 :393-408)
|
|
10
|
-
· 导航税:显式状态记录(`docs/智能的认知过程.md`:84-86)
|
|
10
|
+
· 导航税:显式状态记录(`docs/theory/智能的认知过程.md`:84-86)
|
|
11
11
|
|
|
12
12
|
覆盖:
|
|
13
13
|
A 轨迹:D(t) / dD/dt / d²D/dt² / 情绪 / 四态分布
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""md_cg · 第 16 篇:自我状态层(薄自我 + 富索引)
|
|
3
3
|
|
|
4
4
|
理论出处(本仓原文):
|
|
5
|
-
· `docs/灵枢_自我层定义.md:6`:SELF 层 = 身份 + 价值观 + 图接口,
|
|
5
|
+
· `docs/mdcg/灵枢_自我层定义.md:6`:SELF 层 = 身份 + 价值观 + 图接口,
|
|
6
6
|
不可遗忘、跨会话自动加载,且**是薄的**(不该变成事件仓库)。
|
|
7
7
|
· 智能论 §十一:情绪 = 信息差二阶 d^2D/dt^2;§十:P_gap / P_trust;
|
|
8
8
|
情感 = 信任二阶 d^2T/dt^2。
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
"""代码索引 + 回读端到端测试(P26 · 认知图的代码面)。
|
|
3
3
|
|
|
4
|
-
R1 改造的验收(对照 docs/认知图_索引与工程规范化_计划_v0.1.md):
|
|
4
|
+
R1 改造的验收(对照 docs/mdcg/认知图_索引与工程规范化_计划_v0.1.md):
|
|
5
5
|
|
|
6
6
|
① 渲染即 CCG:`codeindex.render` 必须产出 CCG 6 行。否则
|
|
7
7
|
`judge_qualification` 第一步的 ccg_completeness 会直接判 BLINDSPOT ——
|
|
@@ -208,30 +208,56 @@ def main():
|
|
|
208
208
|
ignite and ignite["parent"] == "Reactor", str(ignite and ignite["parent"]))
|
|
209
209
|
|
|
210
210
|
# ===================================================== ④ 渲染即 CCG
|
|
211
|
-
print("\n【4】render 产出 CCG(R1
|
|
211
|
+
print("\n【4】render 产出 CCG(R1 核心修复 + Phase 0 契约裁决)")
|
|
212
212
|
rendered = codeindex.render(py_item)
|
|
213
213
|
cpl = nodefile.ccg_completeness(rendered)
|
|
214
|
-
check("render
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
214
|
+
check("render 不复制实现正文", "return mass * speed" not in rendered)
|
|
215
|
+
# Phase 0 契约裁决(docs/mdcg/代码评审与条件化注释_契约_v0.1.md):
|
|
216
|
+
# 生效条件只承载**功能前置条件**,不由索引元条件合成。ALPHA 的
|
|
217
|
+
# compute_energy 没有源码 CCG 注释 → 诚实缺该要素,而非被元条件冒充。
|
|
218
|
+
missing = [m for m in nodefile.CCG_REQUIRED
|
|
219
|
+
if m not in cpl["required_present"]]
|
|
220
|
+
check("合成区不冒充生效条件(源码未声明 → 无该行)",
|
|
221
|
+
"# 生效条件:" not in rendered, rendered.split("\n")[0][:60])
|
|
222
|
+
check("缺生效条件被诚实判定(complete=False 且恰缺该要素)",
|
|
223
|
+
cpl["complete"] is False and missing == ["生效条件"], str(missing))
|
|
224
|
+
check("合成区其余 5 要素齐备(不因缺条件整体失效)",
|
|
225
|
+
all(m in cpl["required_present"] for m in nodefile.CCG_MARKS
|
|
226
|
+
if m != "生效条件"), str(cpl["required_present"]))
|
|
227
|
+
|
|
228
|
+
# 条件空间**必须**与 frontmatter 同源:四槽齐备,单槽不是条件空间。
|
|
223
229
|
cs = codeindex.condition_space(py_item)
|
|
224
230
|
check("condition_space 四槽齐备",
|
|
225
231
|
set(cs) == set(nodefile.CONDITION_SLOTS_REQUIRED), str(sorted(cs)))
|
|
226
232
|
synth = nodefile.condition_space_text(cs)
|
|
227
|
-
check("
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
233
|
+
check("四槽合成出非空条件声明(单槽冒充已废止)", bool(synth), synth)
|
|
234
|
+
# 索引元条件**独立承载**且与 CCG 六要素零重名(同源同函数)
|
|
235
|
+
meta_head = f"# {nodefile.INDEX_META_MARK}:"
|
|
236
|
+
meta_line = next((ln for ln in rendered.split("\n")
|
|
237
|
+
if ln.startswith(meta_head)), "")
|
|
238
|
+
check("索引元条件独立成行且非 CCG 字段名",
|
|
239
|
+
bool(meta_line) and not nodefile.is_ccg_mark(nodefile.INDEX_META_MARK),
|
|
240
|
+
meta_line[:70])
|
|
241
|
+
check("索引元条件 = 四槽同源(与 frontmatter 同一纯函数)",
|
|
242
|
+
meta_line == meta_head + nodefile.condition_space_text(
|
|
243
|
+
cs, require_full=False), meta_line[:90])
|
|
232
244
|
check("时间槽用全时窗哨兵(不把写入时刻伪造成条件)",
|
|
233
245
|
nodefile.is_full_time_window(cs.get("time_window")),
|
|
234
246
|
str(cs.get("time_window")))
|
|
247
|
+
# 人工优先:源码声明生效条件时必须置首且胜出(行序压制的反面自证)
|
|
248
|
+
annotated = dict(py_item)
|
|
249
|
+
annotated["comments"] = ["# 生效条件:mass > 0 且 speed >= 0"]
|
|
250
|
+
r2_lines = codeindex.render(annotated).split("\n")
|
|
251
|
+
first_cond = next((ln for ln in r2_lines
|
|
252
|
+
if ln.startswith("# 生效条件:")), "")
|
|
253
|
+
check("源码声明的生效条件置首且逐字保留(未被压制)",
|
|
254
|
+
first_cond == "# 生效条件:mass > 0 且 speed >= 0", first_cond)
|
|
255
|
+
# 合成行按条目实际 kind 构造,避免把 kind 字面量写死在断言里(防漂移)
|
|
256
|
+
synth_head = f"# 功能名:{py_item['name']}({py_item['kind']})"
|
|
257
|
+
check("源码区先于合成区(人工优先的确定性序)",
|
|
258
|
+
synth_head in r2_lines
|
|
259
|
+
and r2_lines.index(first_cond) < r2_lines.index(synth_head),
|
|
260
|
+
str(r2_lines[:3]))
|
|
235
261
|
weak = codeindex.condition_space(js_item)
|
|
236
262
|
check("弱提取在方法槽诚实降级(不冒充编译器)",
|
|
237
263
|
codeindex.LANG_WEAK in weak["observation_tool"]
|
|
@@ -239,22 +265,25 @@ def main():
|
|
|
239
265
|
weak["observation_tool"])
|
|
240
266
|
|
|
241
267
|
# ===================================================== ⑤ 检索 + 资格
|
|
242
|
-
print("\n【5
|
|
268
|
+
print("\n【5】检索资格判定(Phase 0:合成区不冒充生效条件 → 诚实 BLINDSPOT)")
|
|
243
269
|
cg.flush()
|
|
244
270
|
py_nid = codeindex.node_id(py_item)
|
|
245
271
|
read = call_tool(cg, "cg", {"op": "read", "query": "compute_energy", "k": 10})
|
|
246
272
|
hits = [r for r in read.get("results", []) if r["node"]["id"] == py_nid]
|
|
247
273
|
check("代码节点可被检索到(存得进→查得到)", bool(hits),
|
|
248
274
|
f"hits={len(hits)}")
|
|
249
|
-
|
|
250
|
-
|
|
275
|
+
# Phase 0 契约裁决的**代价面**(预期变更,非回归):源码未声明功能
|
|
276
|
+
# 生效条件前,代码条目缺证据 → BLINDSPOT。改造前它靠「索引元条件占用
|
|
277
|
+
# 生效条件字段」取得 DEFER——而那正是「补了注释与没补不可区分」的病根。
|
|
278
|
+
check("源码未声明生效条件 → BLINDSPOT(不再用索引元条件冒充 DEFER)",
|
|
279
|
+
bool(hits) and hits[0]["state"] == "BLINDSPOT",
|
|
251
280
|
str(hits[0]["state"] if hits else None))
|
|
252
281
|
|
|
253
282
|
js_nid = codeindex.node_id(js_item)
|
|
254
283
|
read_js = call_tool(cg, "cg", {"op": "read", "query": "areaOfCircle", "k": 10})
|
|
255
284
|
js_hits = [r for r in read_js.get("results", []) if r["node"]["id"] == js_nid]
|
|
256
|
-
check("
|
|
257
|
-
bool(js_hits) and js_hits[0]["state"] == "
|
|
285
|
+
check("弱提取节点同样诚实缺证据(state=BLINDSPOT)",
|
|
286
|
+
bool(js_hits) and js_hits[0]["state"] == "BLINDSPOT",
|
|
258
287
|
str(js_hits[0]["state"] if js_hits else None))
|
|
259
288
|
|
|
260
289
|
# ===================================================== ⑥ code_ref
|