@furongjun1999/dsh-memory 0.6.0 → 0.7.0
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 +618 -572
- package/codebuddy/CODEBUDDY.md +10 -10
- package/data/policy.json +27 -0
- package/docs/README.md +1 -0
- package/docs/discipline/harnesses.yaml +31 -0
- package/docs/discipline/templates/full.md.tmpl +1 -1
- package/docs/discipline/templates/rules.mdc.tmpl +1 -1
- package/docs/eval/N225_/347/264/242/345/274/225/346/227/245/345/277/227/351/235/236/345/257/271/350/261/241/350/243/205/350/275/275/351/235/242/347/261/273/345/236/213/351/227/270_v1.0.md +418 -0
- package/docs/eval/issue43_/351/273/230/350/256/244/347/255/226/347/225/245/344/270/216/351/224/256/347/261/273/345/236/213/351/227/270_v1.1.md +441 -0
- package/docs/eval/issue43_/351/273/230/350/256/244/347/255/226/347/225/245/345/212/240/350/275/275/344/270/216/345/207/255/346/215/256/346/230/216/346/226/207/351/230/237/345/210/227_v1.0.md +398 -0
- package/docs/eval//344/274/230/345/214/226/347/254/254/344/270/200/346/211/271_/346/216/245/347/272/277/344/270/216/347/255/211/344/273/267/345/217/230/346/215/242_v1.0.md +498 -0
- package/docs/eval//344/274/230/345/214/226/347/254/254/344/270/211/346/211/271_/351/227/250/347/246/201/350/275/254/346/255/243/344/270/216/350/260/203/345/272/246/346/255/242/350/241/200/344/270/216/351/227/250/346/216/247/346/224/266/345/217/243_v1.0.md +669 -0
- package/docs/eval//344/274/230/345/214/226/347/254/254/344/272/214/346/211/271_/344/276/235/350/265/226/351/200/217/344/274/240/344/270/216/345/257/271/346/213/215/345/217/243/345/276/204/344/270/216/350/264/237/347/274/223/345/255/230_v1.0.md +683 -0
- package/docs/eval//345/207/272/350/264/247/351/235/242/345/206/222/347/203/237_/350/277/233/350/264/247/351/227/250/347/246/201_v1.0.md +460 -0
- package/docs/eval//345/217/221/345/270/20307_/345/244/226/351/203/250/346/212/245/345/221/212/345/233/233/346/211/271/344/277/256/345/244/215/344/270/216/346/217/222/344/273/266/351/235/242/345/212/240/345/233/272_v1.0.md +205 -0
- package/docs/eval//345/217/221/345/270/20308_/350/207/252/350/277/255/344/273/243/344/270/216/347/235/241/347/234/240_/345/233/276/346/243/200/347/264/242/350/267/257/344/270/216/346/235/203/351/207/215_v1.0.md +97 -0
- package/docs/eval//345/275/222/344/270/200/345/261/202/347/274/272/347/234/201/347/277/273/345/205/263_/344/277/256/345/244/215/350/256/260/345/275/225_v1.0.md +458 -0
- package/docs/eval//346/200/247/350/203/275/344/270/223/351/241/271_/345/206/267/346/237/245/350/257/242/344/270/216/345/206/205/345/255/230_v1.0.md +218 -0
- package/docs/eval//346/225/205/351/232/234/346/263/250/345/205/245/345/256/236/346/265/213_v1.0.md +10 -0
- package/docs/eval//347/274/226/347/240/201/351/235/242/345/211/215/347/275/256_/345/205/245/345/217/243/350/207/252/344/277/235/350/257/201UTF8/344/270/216/346/226/207/346/234/254open/345/256/210/345/215/253_v1.0.md +646 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v20.md +283 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v21.md +224 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v22.md +223 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v23.md +293 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v24.md +303 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v25.md +230 -0
- package/docs/hive//346/243/200/347/264/242/347/256/227/346/263/225/345/217/243/345/276/204/345/257/271/347/205/247_v0.1.md +136 -11
- 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 +52 -2
- package/docs/hive//350/234/202/345/267/242M6_ingest/345/256/236/346/226/275/350/256/241/345/210/222_v0.1.md +1 -1
- package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +100 -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 +40 -40
- package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +57 -9
- 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 +7 -2
- package/docs/mdcg//347/235/241/347/234/240/345/221/250/346/234/237_/350/277/220/347/273/264/345/211/215/346/217/220/344/270/216/347/273/264/346/212/244/346/214/207/345/215/227_v1.0.md +183 -0
- 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 +39 -3
- package/docs/plans//345/205/250/344/270/255/346/226/207/347/274/226/347/240/201/344/270/216/350/234/202/345/267/242/344/273/273/345/212/241/346/240/207/350/257/206/345/245/221/347/272/246_v2.0.md +220 -0
- package/docs/plans//347/234/237/346/272/220/347/264/242/345/274/225_/351/200/232/347/224/250/346/234/272/345/210/266_v0.3.md +227 -0
- package/docs/plans//347/235/241/347/234/240/344/270/216/350/207/252/350/277/255/344/273/243_/345/212/237/350/203/275/344/274/230/345/214/226/350/256/276/350/256/241_v0.4.md +547 -0
- package/docs/plans//350/234/202/345/267/242/346/250/241/345/236/213/345/257/206/351/222/245/351/205/215/347/275/256/351/235/242_v1.0.md +385 -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 +460 -460
- package/lib/bridge.js +24 -2
- package/lib/hooks.d.ts +31 -2
- package/lib/hooks.js +219 -16
- package/lib/init.js +16 -1
- package/lib/lib/prompt_safety.d.ts +52 -1
- package/lib/lib/prompt_safety.js +76 -1
- package/md_cg/audit.py +652 -379
- package/md_cg/bench6_arms.py +1 -1
- package/md_cg/bench_e2e_locomo_qa.py +11 -4
- package/md_cg/bench_p0.py +1 -1
- package/md_cg/branches.py +2 -2
- package/md_cg/ccgc.py +1071 -1006
- package/md_cg/chain.py +48 -1
- package/md_cg/consistency.py +97 -9
- package/md_cg/consolidate.py +34 -9
- package/md_cg/crypto.py +59 -26
- package/md_cg/docindex.py +16 -1
- package/md_cg/evolution.py +17 -1
- package/md_cg/export.py +1 -1
- package/md_cg/forgetting.py +309 -13
- package/md_cg/freshness.py +511 -0
- package/md_cg/fsutil.py +454 -8
- package/md_cg/generation.py +409 -0
- package/md_cg/hotcache.py +4 -1
- package/md_cg/identity.py +3 -3
- package/md_cg/insight.py +24 -3
- package/md_cg/linkref.py +1 -1
- package/md_cg/logref.py +327 -0
- package/md_cg/mcp_server.py +4261 -3818
- package/md_cg/mdcg.py +4695 -3547
- package/md_cg/mdcos.py +4672 -4159
- package/md_cg/mreview/pipeline.py +15 -1
- package/md_cg/nodefile.py +713 -576
- package/md_cg/protect.py +158 -11
- package/md_cg/protocol.py +41 -2
- package/md_cg/provenance.py +22 -4
- package/md_cg/reach.py +4 -4
- package/md_cg/readcache.py +76 -15
- package/md_cg/reconcile.py +1 -1
- package/md_cg/refindex.py +246 -37
- package/md_cg/refine.py +1 -1
- package/md_cg/routing.py +32 -5
- package/md_cg/run_tests.py +17 -0
- package/md_cg/scrub.py +30 -3
- package/md_cg/security.py +47 -1
- package/md_cg/self_state.py +5 -5
- package/md_cg/semantic/canonical.py +22 -0
- package/md_cg/semantic/unify.py +73 -22
- package/md_cg/semantic/unify_fixture.json +25 -0
- package/md_cg/sleep.py +1297 -0
- package/md_cg/sources.py +23 -6
- package/md_cg/srcindex.py +352 -0
- package/md_cg/stg.py +47 -3
- package/md_cg/subgraph.py +2 -2
- package/md_cg/sustain.py +1436 -1168
- package/md_cg/tasks.py +469 -470
- package/md_cg/test_auto_defaults.py +424 -0
- package/md_cg/test_b1_auto_id_multiproc.py +277 -0
- package/md_cg/test_b1b2_write_face.py +417 -0
- package/md_cg/test_b2_sensitivity_landing.py +223 -0
- package/md_cg/test_b3_merge_keeps_content.py +576 -0
- package/md_cg/test_b4_shard_dir_selfheal.py +843 -0
- package/md_cg/test_b4_shard_dir_selfheal_guard.py +238 -0
- package/md_cg/test_boundary_hit.py +410 -0
- package/md_cg/test_c3_transient_read_negative.py +793 -0
- package/md_cg/test_c8_search_rrf_gates.py +502 -0
- package/md_cg/test_ccg_form_parity.py +188 -0
- package/md_cg/test_ccgc.py +28 -3
- package/md_cg/test_en_pipeline.py +22 -13
- package/md_cg/test_generation_guard.py +352 -0
- package/md_cg/test_govern_directread.py +17 -4
- package/md_cg/test_h2_session_view_norm.py +233 -0
- package/md_cg/test_h4_sustain_snapshot.py +1387 -0
- package/md_cg/test_hive_ingest.py +285 -285
- package/md_cg/test_issue39_utf8_stdio.py +307 -16
- package/md_cg/test_issue43_default_policy.py +865 -0
- package/md_cg/test_legacy_p3_node_id_type.py +375 -0
- package/md_cg/test_linkref.py +10 -3
- package/md_cg/test_lock.py +2 -2
- package/md_cg/test_logref.py +1109 -0
- package/md_cg/test_m3_h9_bucket_health_protect_mark.py +301 -0
- package/md_cg/test_m3_h9_semantic_guard.py +525 -0
- package/md_cg/test_mr_m2.py +15 -3
- package/md_cg/test_n130_verify_falsified_protect.py +1 -1
- package/md_cg/test_n139_dek_provision_failclosed.py +185 -0
- package/md_cg/test_n176_link_trust.py +221 -0
- package/md_cg/test_n178_units_jobid_gate.py +212 -0
- package/md_cg/test_n184_keys_concurrent_provision.py +307 -0
- package/md_cg/test_n195_writepath_reload.py +283 -0
- package/md_cg/test_n196_stale_gate_skip.py +169 -0
- package/md_cg/test_n197_n208_write_face_gates.py +471 -0
- package/md_cg/test_n198_tokens_corrupt_failclosed.py +225 -0
- package/md_cg/test_n199_tokens_concurrent_write.py +378 -0
- package/md_cg/test_n201_proposal_visibility.py +382 -0
- package/md_cg/test_n202_session_notes_visibility.py +461 -0
- package/md_cg/test_n204_n205_n226_n227_n228_n229_exit_gates.py +542 -0
- package/md_cg/test_n206_stdio_jsonrpc_type.py +403 -0
- package/md_cg/test_n209_verify_write_face_gates.py +461 -0
- package/md_cg/test_n212_n213_n224_generation_gates.py +519 -0
- package/md_cg/test_n214_n215_n221_n222_write_face_gates.py +563 -0
- package/md_cg/test_n225_nonobject_load.py +1110 -0
- package/md_cg/test_n230_dirty_replay.py +375 -0
- package/md_cg/test_n62_tenant_bind_failclosed.py +200 -0
- package/md_cg/test_neg_condition_hits.py +333 -0
- package/md_cg/test_neg_tail_honesty.py +663 -0
- package/md_cg/test_none_id_write_guard.py +4 -3
- package/md_cg/test_opt_batch1_md_cg.py +451 -0
- package/md_cg/test_p1.py +5 -5
- package/md_cg/test_p11_consistency.py +161 -12
- package/md_cg/test_p26_refindex.py +2 -2
- package/md_cg/test_p27_docindex.py +777 -774
- package/md_cg/test_p28_refcheck.py +740 -13
- package/md_cg/test_p29_session_ingest_export.py +2 -2
- package/md_cg/test_p2_mcp.py +12 -1
- package/md_cg/test_p2_six_elements.py +463 -0
- package/md_cg/test_p30_maintain.py +33 -2
- package/md_cg/test_p31_insight.py +1 -0
- package/md_cg/test_p3_legacy_closure.py +433 -0
- package/md_cg/test_p4_freshness.py +680 -0
- package/md_cg/test_p8_subgraph_chain.py +14 -1
- package/md_cg/test_p9c_dedup_hints.py +276 -0
- package/md_cg/test_policy_required_ccg.py +426 -0
- package/md_cg/test_protocol.py +22 -0
- package/md_cg/test_rank_parity_score_mode.py +522 -0
- package/md_cg/test_read_face_input_gates.py +363 -0
- package/md_cg/test_read_face_semantics.py +489 -0
- package/md_cg/test_recall_face_guards.py +812 -0
- package/md_cg/test_rejected_credential_forms.py +188 -0
- package/md_cg/test_rejected_redact.py +146 -0
- package/md_cg/test_retr_s1b.py +2 -2
- package/md_cg/test_retr_s5.py +20 -7
- package/md_cg/test_review_conformance.py +21 -3
- package/md_cg/test_security_audit_v21.py +2 -2
- package/md_cg/test_semantic_canonical.py +5 -3
- package/md_cg/test_server_version.py +67 -0
- package/md_cg/test_sleep.py +611 -0
- package/md_cg/test_sleep_p1.py +784 -0
- package/md_cg/test_srcindex.py +171 -0
- package/md_cg/test_tenant_env_override_warn.py +63 -50
- package/md_cg/test_time_core_lint.py +968 -0
- package/md_cg/test_token_lowercase_form.py +315 -0
- package/md_cg/test_unify_default_off.py +701 -0
- package/md_cg/test_unify_scope.py +182 -0
- package/md_cg/test_v21r1_package_version.py +310 -0
- package/md_cg/test_writepipe.py +10 -4
- package/md_cg/tokens.py +225 -95
- package/md_cg/tool_face.py +4 -4
- package/md_cg/trust.py +49 -5
- package/md_cg/units.py +204 -6
- package/md_cg/weights.py +4 -4
- package/md_cg/whitebox_kb/aeis_core/time_core.py +8 -0
- package/md_cg/whitebox_kb/wisdom/knowledge_points.py +1 -1
- package/md_cg/writelimit.py +42 -8
- package/md_cg/writepipe.py +651 -554
- package/package.json +4 -2
- package/skills/plugin.json +1 -1
- package/src/bridge.ts +25 -2
- package/src/hooks.ts +229 -16
- package/src/init.ts +15 -1
- package/src/lib/prompt_safety.ts +88 -1
- package/utf8_boot.py +237 -0
- package/zcode/AGENTS.md +10 -10
|
@@ -179,7 +179,20 @@ def main():
|
|
|
179
179
|
for items in (dmeta.get("provenance") or {}).values():
|
|
180
180
|
for p in items:
|
|
181
181
|
dpaths.add(p.get("path"))
|
|
182
|
-
|
|
182
|
+
# P3-causal(2026-10-01):chain 路按裁定 9「全进默认检索」**进缺省集**
|
|
183
|
+
# ——本条断言随口径反转(原断言「默认检索路不含 chain」是 P3 之前的基线,
|
|
184
|
+
# 逐字留档于此)。反转后仍可判的两件事:①缺省调用确实走到 chain 路;
|
|
185
|
+
# ②显式不含 chain 时该路不出现(分路开关保留)。
|
|
186
|
+
check("默认检索路**含** chain(P3:进缺省集;原断言为「不含」)",
|
|
187
|
+
"chain" in dpaths, str(sorted(dpaths)))
|
|
188
|
+
_xr, xmeta = cg.search_rrf(
|
|
189
|
+
"数据库在运行", k=8,
|
|
190
|
+
paths=("lexical", "bucket", "entity", "graph"))
|
|
191
|
+
xpaths = {p.get("path")
|
|
192
|
+
for items in (xmeta.get("provenance") or {}).values()
|
|
193
|
+
for p in items}
|
|
194
|
+
check("显式不含 chain 时该路不出现(分路开关保留)",
|
|
195
|
+
"chain" not in xpaths, str(sorted(xpaths)))
|
|
183
196
|
|
|
184
197
|
check("公开 API:subgraph_expand/flatten/validate/roots",
|
|
185
198
|
all(hasattr(cg, n) for n in ("subgraph_expand", "subgraph_flatten",
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""md_cg · P-9b 去重可见性守卫:直写 dup_of 提示 + gated 路径两处静默洞
|
|
3
|
+
|
|
4
|
+
背景(探针实测,2026-09-30)
|
|
5
|
+
---------------------------
|
|
6
|
+
① **直写**(`mdcg_remember(gated=false)` 与 `cg(op=write, gated=false)` 的链尾
|
|
7
|
+
执行器)此前返回体**只有 id**——「同内容以异 id 再写一次」在盘面上变两个
|
|
8
|
+
节点,而调用方拿不到任何提示(`add` 只回 id 字符串)。
|
|
9
|
+
这是**文档化现状**(`writelimit.py` 模块头注 :9-12:限流/同构聚合只作用
|
|
10
|
+
contextual 层,knowledge 等手动纪律写入不受限)⇒ **不许改写入语义**。
|
|
11
|
+
② gated 路径(默认路径)有两处**静默洞**:
|
|
12
|
+
(a) 同 id 覆写:`redundancy(exclude=node_id)` 自排除 ⇒ 该层只此一节点时
|
|
13
|
+
`compared=0`、`duplicate_with=None`、`duplicate_ratio=0.0`——「覆写」与
|
|
14
|
+
「全新写入」在裁决里完全不可区分(审计面全 null);
|
|
15
|
+
(b) `importance≥PROTECT_IMPORTANCE(0.7)` 的「保护优先」分支**排在冗余判定
|
|
16
|
+
之前** ⇒ 高重要度内容的重复写直接 ACCEPT,绕过 MERGE/DROP(实测:dup=1.0
|
|
17
|
+
且节点数 +1),审计面只剩一句「触发不可遗忘保护」。
|
|
18
|
+
|
|
19
|
+
本批处置(依据见 `forgetting.assess` 的 docstring 与 `md_cg/mcp_server.py` 的
|
|
20
|
+
分支注释):**只补可见性读数,不动任何落盘行为与 verdict**——
|
|
21
|
+
· 直写:返回体附 `dup_of`/`dup_ratio`/`dup_compared`/`dup_hint` +
|
|
22
|
+
`overwrite_of`/`overwrite_ratio`;
|
|
23
|
+
· gated (a):`gate.entropy.overwrite_of`/`overwrite_ratio` 非 null;
|
|
24
|
+
· gated (b):该分支返回 `gate.dedup_skipped`(reason=protect_importance +
|
|
25
|
+
去重判据读数),reason 文案显式写出「因保护优先未走去重」。
|
|
26
|
+
|
|
27
|
+
为何 (b) 选「标注」而不是「把 PROTECT 挪到冗余判定之后」:挪位会削弱
|
|
28
|
+
「不可遗忘保护」(高重要度内容将可被 DROP/并入他节点),与 PROTECT_IMPORTANCE
|
|
29
|
+
及 `writelimit.py` 头注的跨模块「保护优先」口径分叉,且 DROP 不可逆——缺陷本体
|
|
30
|
+
是「静默」而非「保护」,标注即可消除且零回归面。本测 ⑤ **钉住这个决定**:
|
|
31
|
+
高重要度近重复的 verdict 必须仍是 ACCEPT(若被挪位 ⇒ 变 MERGE ⇒ 立刻红)。
|
|
32
|
+
|
|
33
|
+
判据来源:现成字段 `gate.entropy.duplicate_with/.duplicate_ratio/.compared` 与
|
|
34
|
+
`gate.redundancy.with/.max`(不新增重复度算法;新增读数复用 `forgetting` 的
|
|
35
|
+
同一实现 redundancy / prior_node / self_coverage)。
|
|
36
|
+
|
|
37
|
+
运行:python -m md_cg.test_p9c_dedup_hints
|
|
38
|
+
"""
|
|
39
|
+
from __future__ import annotations
|
|
40
|
+
|
|
41
|
+
import json
|
|
42
|
+
import os
|
|
43
|
+
import shutil
|
|
44
|
+
import tempfile
|
|
45
|
+
import traceback
|
|
46
|
+
|
|
47
|
+
from . import forgetting, writepipe
|
|
48
|
+
from .mdcos import MdCGOS, MdCGSecure
|
|
49
|
+
from .security import Principal
|
|
50
|
+
|
|
51
|
+
PASS = 0
|
|
52
|
+
FAIL = 0
|
|
53
|
+
FAILS = []
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def check(name, cond, detail=""):
|
|
57
|
+
global PASS, FAIL
|
|
58
|
+
if cond:
|
|
59
|
+
PASS += 1
|
|
60
|
+
print(f" [PASS] {name}" + (f" · {detail}" if detail else ""))
|
|
61
|
+
else:
|
|
62
|
+
FAIL += 1
|
|
63
|
+
FAILS.append(name)
|
|
64
|
+
print(f" [FAIL] {name} · {detail}")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def ccg(title, body):
|
|
68
|
+
return (f"# 功能名:{title}\n# 生效条件:任意情境\n# 子功能:验收\n"
|
|
69
|
+
f"# 执行:直接调用\n# 验证方式:test\n# 不适用条件:无\n{body}\n")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# 直写路径 A(mdcg_remember gated=false)用:无策略闸,正文无需 PASSED
|
|
73
|
+
BODY = ccg("编译缓存清理", "清理编译缓存目录释放磁盘空间,超过 2GB 时按 mtime 删除最旧分片")
|
|
74
|
+
# 直写路径 B(cg(op=write))用:必须过 audit 闸(策略 required 含 PASSED)
|
|
75
|
+
BODY_PASSED = ccg("编译缓存清理", "PASSED 清理编译缓存目录释放磁盘空间,超过 2GB 时删除最旧分片")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _mk_secure(root):
|
|
79
|
+
p = Principal(tenant="default", actor="t_designer", role="designer",
|
|
80
|
+
can_write=True, can_admin=True)
|
|
81
|
+
return MdCGSecure(root, principal=p)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _policy(tmp, required=("PASSED",), forbidden=()):
|
|
85
|
+
path = os.path.join(tmp, "policy_p9c.json")
|
|
86
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
87
|
+
json.dump({"forbidden": list(forbidden), "required": list(required)}, f)
|
|
88
|
+
return path
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _run(tmp):
|
|
92
|
+
from . import mcp_server
|
|
93
|
+
|
|
94
|
+
# ============ A. 直写路径:mdcg_remember(gated=false) ============
|
|
95
|
+
print("\n[A] 直写路径 A(mdcg_remember gated=false):同内容异 id 的提示")
|
|
96
|
+
cg = _mk_secure(os.path.join(tmp, "a"))
|
|
97
|
+
cg.add("k_base", BODY, layer="knowledge", importance=0.5)
|
|
98
|
+
n_before = len(cg.index["nodes"])
|
|
99
|
+
res = mcp_server._dispatch(cg, "mdcg_remember",
|
|
100
|
+
{"content": BODY, "node_id": "k_dup",
|
|
101
|
+
"gated": False, "layer": "knowledge",
|
|
102
|
+
"content_kind": "text"})
|
|
103
|
+
check("A1 直写仍成功落盘(不改写入语义)",
|
|
104
|
+
res.get("ok") is True and cg.get("k_dup") is not None, repr(res)[:160])
|
|
105
|
+
check("A2 盘面仍新增节点(去重语义未被改动)",
|
|
106
|
+
len(cg.index["nodes"]) == n_before + 1,
|
|
107
|
+
f"{n_before} -> {len(cg.index['nodes'])}")
|
|
108
|
+
check("A3 返回体带 dup_of 指向已存在节点(修复面)",
|
|
109
|
+
res.get("dup_of") == "k_base", repr(res)[:200])
|
|
110
|
+
check("A4 dup_ratio 为现成重复度读数(≥ DUP_MERGE)",
|
|
111
|
+
isinstance(res.get("dup_ratio"), float)
|
|
112
|
+
and res["dup_ratio"] >= forgetting.DUP_MERGE, repr(res.get("dup_ratio")))
|
|
113
|
+
check("A5 dup_hint 如实说明「直写不去重」的文档化现状",
|
|
114
|
+
isinstance(res.get("dup_hint"), str) and "直写" in res["dup_hint"]
|
|
115
|
+
and "writelimit" in res["dup_hint"], repr(res.get("dup_hint"))[:160])
|
|
116
|
+
|
|
117
|
+
# 无重复内容:不得凭空报 dup(判据要有判别力)
|
|
118
|
+
res2 = mcp_server._dispatch(cg, "mdcg_remember",
|
|
119
|
+
{"content": ccg("奇点事故复盘", "首次观测到未知内存泄漏,与既有记忆无重叠"),
|
|
120
|
+
"node_id": "k_fresh", "gated": False,
|
|
121
|
+
"layer": "knowledge", "content_kind": "text"})
|
|
122
|
+
check("A6 无重复时不报 dup_of(避免假提示)",
|
|
123
|
+
res2.get("ok") is True and "dup_of" not in res2, repr(res2)[:160])
|
|
124
|
+
|
|
125
|
+
# 同 id 覆写:overwrite_of / overwrite_ratio
|
|
126
|
+
res3 = mcp_server._dispatch(cg, "mdcg_remember",
|
|
127
|
+
{"content": BODY, "node_id": "k_base",
|
|
128
|
+
"gated": False, "layer": "knowledge",
|
|
129
|
+
"content_kind": "text"})
|
|
130
|
+
check("A7 同 id 覆写回 overwrite_of(原本无从区分覆写与新建)",
|
|
131
|
+
res3.get("overwrite_of") == "k_base", repr(res3)[:200])
|
|
132
|
+
check("A8 同 id 同内容覆写:overwrite_ratio ≈ 1.0(空写可见)",
|
|
133
|
+
res3.get("overwrite_ratio") == 1.0, repr(res3.get("overwrite_ratio")))
|
|
134
|
+
res4 = mcp_server._dispatch(cg, "mdcg_remember",
|
|
135
|
+
{"content": ccg("编译缓存清理", "清理编译缓存目录释放磁盘空间,超过 8GB 时按 mtime 删除最旧分片"),
|
|
136
|
+
"node_id": "k_base", "gated": False,
|
|
137
|
+
"layer": "knowledge", "content_kind": "text"})
|
|
138
|
+
check("A9 同 id 改内容覆写:overwrite_ratio < 1.0(真改可见)",
|
|
139
|
+
isinstance(res4.get("overwrite_ratio"), float)
|
|
140
|
+
and res4["overwrite_ratio"] < 1.0, repr(res4.get("overwrite_ratio")))
|
|
141
|
+
|
|
142
|
+
# ============ B. 直写路径:cg(op=write) 链尾执行器 ============
|
|
143
|
+
print("\n[B] 直写路径 B(cg(op=write, gated=false) 链尾执行器)")
|
|
144
|
+
old_policy = os.environ.get("MDCG_POLICY_FILE")
|
|
145
|
+
os.environ["MDCG_POLICY_FILE"] = _policy(tmp)
|
|
146
|
+
try:
|
|
147
|
+
pipe = writepipe.install_default_gates(writepipe.WritePipeline())
|
|
148
|
+
cgb = _mk_secure(os.path.join(tmp, "b"))
|
|
149
|
+
cgb.add("w_base", BODY_PASSED, layer="knowledge", importance=0.5)
|
|
150
|
+
out = pipe.execute(cgb, {"content_kind": "text", "content": BODY_PASSED,
|
|
151
|
+
"gated": False, "layer": "knowledge"})
|
|
152
|
+
check("B1 直写经链:committed + verdict 不变",
|
|
153
|
+
out.get("committed") is True and out.get("verdict") is not None,
|
|
154
|
+
repr(out)[:200])
|
|
155
|
+
check("B2 经链直写也带 dup_of(第二处落盘点同样接线上)",
|
|
156
|
+
out.get("dup_of") == "w_base", repr(out)[:200])
|
|
157
|
+
check("B3 经链直写 dup_ratio 读数存在",
|
|
158
|
+
isinstance(out.get("dup_ratio"), float)
|
|
159
|
+
and out["dup_ratio"] >= forgetting.DUP_MERGE, repr(out.get("dup_ratio")))
|
|
160
|
+
out2 = pipe.execute(cgb, {"content_kind": "text",
|
|
161
|
+
"content": BODY_PASSED, "gated": False,
|
|
162
|
+
"node_id": "w_base", "layer": "knowledge"})
|
|
163
|
+
check("B4 经链直写覆写读数存在",
|
|
164
|
+
out2.get("overwrite_of") == "w_base"
|
|
165
|
+
and out2.get("overwrite_ratio") == 1.0, repr(out2)[:200])
|
|
166
|
+
# 无重复不报 dup
|
|
167
|
+
fresh = ccg("奇点事故复盘二", "PASSED 首次观测到未知泄漏,与既有记忆无重叠")
|
|
168
|
+
out3 = pipe.execute(cgb, {"content_kind": "text", "content": fresh,
|
|
169
|
+
"gated": False, "layer": "knowledge"})
|
|
170
|
+
check("B5 经链直写无重复时不报 dup_of",
|
|
171
|
+
out3.get("committed") is True and "dup_of" not in out3,
|
|
172
|
+
repr(out3)[:160])
|
|
173
|
+
finally:
|
|
174
|
+
if old_policy is None:
|
|
175
|
+
os.environ.pop("MDCG_POLICY_FILE", None)
|
|
176
|
+
else:
|
|
177
|
+
os.environ["MDCG_POLICY_FILE"] = old_policy
|
|
178
|
+
|
|
179
|
+
# ============ C. gated 洞 (a):同 id 覆写的裁决不再全 null ============
|
|
180
|
+
print("\n[C] gated (a):同 id 覆写 → entropy.overwrite_of(不再静默全 null)")
|
|
181
|
+
cg3 = MdCGOS(os.path.join(tmp, "c"))
|
|
182
|
+
cg3.add("k_ov", BODY, layer="knowledge", importance=0.5)
|
|
183
|
+
r = cg3.remember_gated("k_ov", BODY, layer="knowledge", role="user")
|
|
184
|
+
ent = r["gate"]["entropy"]
|
|
185
|
+
check("C1 覆写情形 entropy.overwrite_of 指向既有 id",
|
|
186
|
+
ent.get("overwrite_of") == "k_ov", repr(ent)[:220])
|
|
187
|
+
check("C2 覆写情形 overwrite_ratio 有值(1.0=逐字同构的重写)",
|
|
188
|
+
ent.get("overwrite_ratio") == 1.0, repr(ent.get("overwrite_ratio")))
|
|
189
|
+
check("C3 并未改动去重判据本身:自排除仍在(duplicate_with 依旧 None、compared 0)",
|
|
190
|
+
ent.get("duplicate_with") is None and ent.get("compared") == 0,
|
|
191
|
+
repr({k: ent.get(k) for k in ("duplicate_with", "compared")}))
|
|
192
|
+
check("C4 verdict 不变(覆写语义未动)", r["verdict"] == "ACCEPT",
|
|
193
|
+
f"{r['verdict']} · {r['gate']['reason']}")
|
|
194
|
+
check("C5 同 id 异内容覆写:overwrite_ratio < 1.0",
|
|
195
|
+
forgetting.assess(cg3, BODY.replace("2GB", "8GB"), layer="knowledge",
|
|
196
|
+
role="user", node_id="k_ov")["entropy"]["overwrite_ratio"] < 1.0,
|
|
197
|
+
str(forgetting.assess(cg3, BODY.replace("2GB", "8GB"), layer="knowledge",
|
|
198
|
+
role="user", node_id="k_ov")["entropy"]["overwrite_ratio"]))
|
|
199
|
+
|
|
200
|
+
# ============ D. gated 洞 (b):保护优先不静默 ============
|
|
201
|
+
print("\n[D] gated (b):importance≥0.7 的近重复 → dedup_skipped 标注")
|
|
202
|
+
cg4 = MdCGOS(os.path.join(tmp, "d"))
|
|
203
|
+
cg4.add("c_dup", BODY, layer="contextual", importance=0.5)
|
|
204
|
+
n_before = len(cg4.index["nodes"])
|
|
205
|
+
r2 = cg4.remember_gated("c_new", BODY, layer="contextual", role="user",
|
|
206
|
+
importance_hint=0.9)
|
|
207
|
+
g = r2["gate"]
|
|
208
|
+
dk = g.get("dedup_skipped")
|
|
209
|
+
check("D1 保护优先分支**仍** ACCEPT(保护语义不变——未被挪到冗余判定之后)",
|
|
210
|
+
r2["verdict"] == "ACCEPT", f"{r2['verdict']} · {g['reason']}")
|
|
211
|
+
check("D2 该分支不再静默:dedup_skipped 存在且 reason=protect_importance",
|
|
212
|
+
isinstance(dk, dict) and dk.get("reason") == "protect_importance",
|
|
213
|
+
repr(dk)[:220])
|
|
214
|
+
check("D3 标注带现成去重读数(duplicate_with 指向既有节点)",
|
|
215
|
+
isinstance(dk, dict) and dk.get("duplicate_with") == "c_dup"
|
|
216
|
+
and dk.get("duplicate_ratio", 0) >= forgetting.DUP_MERGE,
|
|
217
|
+
repr(dk)[:220])
|
|
218
|
+
check("D4 reason 文案显式写出「因保护优先未走去重」",
|
|
219
|
+
"保护优先" in g["reason"] and "未走去重" in g["reason"], g["reason"])
|
|
220
|
+
check("D5 落盘行为不变:仍新建节点(保护优先本就不并入)",
|
|
221
|
+
len(cg4.index["nodes"]) == n_before + 1,
|
|
222
|
+
f"{n_before} -> {len(cg4.index['nodes'])}")
|
|
223
|
+
|
|
224
|
+
# 保护优先 + 无近重复:仍标注(结构不变量),但如实说「无近重复」
|
|
225
|
+
r3 = cg4.remember_gated("c_fresh", ccg("奇点事故复盘三", "PASSED 首次观测到未知泄漏,与既有记忆无重叠"),
|
|
226
|
+
layer="contextual", role="user", importance_hint=0.9)
|
|
227
|
+
dk3 = r3["gate"].get("dedup_skipped")
|
|
228
|
+
check("D6 保护优先 + 无近重复:仍带 dedup_skipped 且 duplicate_with 为 None",
|
|
229
|
+
isinstance(dk3, dict) and dk3.get("duplicate_with") is None,
|
|
230
|
+
repr(dk3)[:220])
|
|
231
|
+
|
|
232
|
+
# ============ E. 结构不变量:dedup_skipped 只在 PROTECT 分支出现 ============
|
|
233
|
+
print("\n[E] 结构不变量:dedup_skipped 仅 PROTECT 分支(不多不少)")
|
|
234
|
+
cg5 = MdCGOS(os.path.join(tmp, "e"))
|
|
235
|
+
cg5.add("p_dup", BODY, layer="contextual", importance=0.5)
|
|
236
|
+
cases = [
|
|
237
|
+
("保护优先(0.9)+ 近重复", BODY, 0.9, True),
|
|
238
|
+
("保护优先(0.7 边界)+ 全新", ccg("边界探针", "PASSED 全新的边界用例内容"), 0.7, True),
|
|
239
|
+
("非保护(0.6)+ 近重复", BODY, 0.6, False),
|
|
240
|
+
("非保护(0.1)+ 近重复", BODY, 0.1, False),
|
|
241
|
+
]
|
|
242
|
+
for name, content, hint, expect in cases:
|
|
243
|
+
g5 = forgetting.assess(cg5, content, layer="contextual", role="user",
|
|
244
|
+
importance_hint=hint, node_id=None)
|
|
245
|
+
got = g5.get("dedup_skipped") is not None
|
|
246
|
+
check(f"E · {name}", got is expect,
|
|
247
|
+
f"dedup_skipped={'有' if got else '无'}(期望 {'有' if expect else '无'})"
|
|
248
|
+
f" · verdict={g5['verdict']}")
|
|
249
|
+
check("E · entropy 恒带 overwrite_of 键(无覆写时为 None,不新增缺键)",
|
|
250
|
+
"overwrite_of" in g5["entropy"] and g5["entropy"]["overwrite_of"] is None,
|
|
251
|
+
str(g5["entropy"].get("overwrite_of")))
|
|
252
|
+
check("E · prior_node 单点:空 id / 不存在 id 一律 None",
|
|
253
|
+
forgetting.prior_node(cg5, None) is None
|
|
254
|
+
and forgetting.prior_node(cg5, "") is None
|
|
255
|
+
and forgetting.prior_node(cg5, "不存在的_id") is None
|
|
256
|
+
and forgetting.prior_node(cg5, "p_dup") == "p_dup")
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def main():
|
|
260
|
+
tmp = tempfile.mkdtemp(prefix="mdcg_p9c_")
|
|
261
|
+
try:
|
|
262
|
+
_run(tmp)
|
|
263
|
+
except Exception:
|
|
264
|
+
traceback.print_exc()
|
|
265
|
+
globals()["FAIL"] += 1
|
|
266
|
+
FAILS.append("未捕获异常")
|
|
267
|
+
finally:
|
|
268
|
+
shutil.rmtree(tmp, ignore_errors=True)
|
|
269
|
+
print(f"\n==== P9c 结果:{PASS} 通过 / {FAIL} 失败 ====")
|
|
270
|
+
if FAILS:
|
|
271
|
+
print("失败项:" + "、".join(FAILS))
|
|
272
|
+
return 1 if FAIL else 0
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
if __name__ == "__main__":
|
|
276
|
+
raise SystemExit(main())
|