@furongjun1999/dsh-memory 0.4.7 → 0.4.8
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 +92 -37
- package/codebuddy/CODEBUDDY.md +195 -185
- 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 +215 -152
- package/docs/discipline/templates/full.md.tmpl +60 -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/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/}/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/{README → mdcg/README}/350/257/246/347/273/206/347/211/210_v0.4.5.md +9 -9
- 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//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +261 -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.4.md +148 -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/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/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 +3 -3
- 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 +34 -6
- 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 +1 -1
- package/lib/hooks.d.ts +5 -0
- package/lib/hooks.js +10 -1
- package/lib/lib/prompt_safety.d.ts +48 -0
- package/lib/lib/prompt_safety.js +62 -0
- package/md_cg/audit.py +76 -2
- package/md_cg/bench_membench.py +10 -5
- package/md_cg/bench_progressive.py +48 -9
- package/md_cg/branches.py +275 -0
- package/md_cg/ccgc.py +884 -0
- package/md_cg/conformance.py +662 -0
- package/md_cg/consistency.py +1 -1
- package/md_cg/corpus.py +1 -1
- package/md_cg/eval_common.py +6 -5
- package/md_cg/forgetting.py +11 -3
- package/md_cg/fsutil.py +63 -1
- package/md_cg/identity.py +2 -2
- package/md_cg/insight.py +2 -2
- package/md_cg/lifecycle.py +262 -0
- package/md_cg/mcp_server.py +547 -140
- package/md_cg/mdcg.py +206 -18
- package/md_cg/mdcos.py +512 -50
- package/md_cg/metacognition.py +2 -2
- package/md_cg/mreview/__init__.py +25 -0
- package/md_cg/mreview/__main__.py +107 -0
- package/md_cg/mreview/bundle.py +170 -0
- package/md_cg/mreview/candidates.py +253 -0
- package/md_cg/mreview/govern.py +674 -0
- package/md_cg/mreview/locate.py +905 -0
- package/md_cg/mreview/pipeline.py +701 -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 +238 -0
- package/md_cg/nodefile.py +38 -0
- package/md_cg/predict.py +24 -6
- package/md_cg/protect.py +4 -4
- package/md_cg/refindex.py +41 -2
- package/md_cg/scrub.py +5 -1
- package/md_cg/self_state.py +1 -1
- package/md_cg/semantic/en_normalizer.py +85 -25
- package/md_cg/sustain.py +18 -0
- package/md_cg/tasks.py +447 -0
- package/md_cg/test_action_derive.py +203 -0
- package/md_cg/test_audit_rotate.py +270 -0
- package/md_cg/test_branches.py +249 -0
- package/md_cg/test_ccg_perturb.py +1 -1
- package/md_cg/test_ccgc.py +423 -0
- package/md_cg/test_conformance.py +343 -0
- package/md_cg/test_en_pipeline.py +24 -0
- package/md_cg/test_health_scale.py +173 -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_mr_m1.py +679 -0
- package/md_cg/test_mr_m2.py +587 -0
- package/md_cg/test_mr_m3.py +703 -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 +1 -1
- package/md_cg/test_p27_docindex.py +22 -2
- 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_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_read_clip.py +137 -0
- package/md_cg/test_review_conformance.py +310 -0
- package/md_cg/test_tasks.py +409 -0
- package/md_cg/test_tool_face.py +189 -0
- package/md_cg/test_twophase.py +286 -0
- package/md_cg/test_writepipe.py +210 -0
- package/md_cg/theory.py +1 -1
- package/md_cg/tokens.py +95 -5
- package/md_cg/tool_face.py +250 -0
- package/md_cg/twophase.py +221 -0
- package/md_cg/units.py +546 -0
- package/md_cg/vision_evidence.py +1 -1
- package/md_cg/weights.py +1 -1
- package/md_cg/whitebox.py +1 -1
- package/md_cg/whitebox_kb/data/verify_cache.json +28 -0
- package/md_cg/whitebox_kb/data/verify_savings.jsonl +46 -0
- package/md_cg/whitebox_kb/wisdom/audit_log/chain_heat.json +10 -10
- package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db-shm +0 -0
- package/md_cg/whitebox_kb/wisdom/wisdom-book-cloud.db-wal +0 -0
- package/md_cg/writelimit.py +19 -3
- package/md_cg/writepipe.py +372 -0
- package/package.json +1 -1
- package/src/hooks.ts +10 -1
- package/src/lib/prompt_safety.ts +62 -0
- package/zcode/AGENTS.md +195 -185
- 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
|
@@ -91,15 +91,18 @@ def exp_locomo():
|
|
|
91
91
|
print("[progressive] 实验一 locomo-zh-500 · 语料 %d / 题 %d"
|
|
92
92
|
% (len(corpus), len(questions)))
|
|
93
93
|
|
|
94
|
+
pool_sizes = [] # G1 各阶段候选池大小(统计面)
|
|
95
|
+
|
|
94
96
|
def rank_fn(used):
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
ranked = full_rank(frozenset(used), docs)[:20]
|
|
98
|
+
pool_sizes.append(len(ranked))
|
|
99
|
+
return [(nid, 0.0) for nid in ranked]
|
|
97
100
|
|
|
98
101
|
st_g0 = {"h1": 0, "h5": 0, "h10": 0, "rr": 0.0}
|
|
99
102
|
st_g2 = dict(st_g0)
|
|
100
103
|
st_i = dict(st_g0)
|
|
101
104
|
st_f = dict(st_g0)
|
|
102
|
-
steps_sum = conv = n = 0
|
|
105
|
+
steps_sum = conv = n = fa10_sum = 0
|
|
103
106
|
for q in questions:
|
|
104
107
|
ev = set(q.get("evidence_turns") or [])
|
|
105
108
|
qa = [w for w in zh_map_en(str(q.get("question") or ""),
|
|
@@ -117,8 +120,11 @@ def exp_locomo():
|
|
|
117
120
|
ratio=0.5, k=10, max_stages=4)
|
|
118
121
|
_agg(rank_of(ev, full_rank(frozenset(tr["stages"][0]["used"]),
|
|
119
122
|
docs)), st_i)
|
|
120
|
-
|
|
121
|
-
|
|
123
|
+
fin_all = full_rank(frozenset(tr["stages"][-1]["used"]), docs)
|
|
124
|
+
_agg(rank_of(ev, fin_all), st_f)
|
|
125
|
+
# 保守 false_accept 口径:final top10 内非 gold 条数(本语料无资格
|
|
126
|
+
# 判定面,非 gold 全计为假接受——上界,见打印行口径注明)
|
|
127
|
+
fa10_sum += sum(1 for nid in fin_all[:10] if nid not in ev)
|
|
122
128
|
steps_sum += len(tr["added"])
|
|
123
129
|
conv += 1 if (tr["converged"] or len(tr["added"]) < 3) else 0
|
|
124
130
|
|
|
@@ -130,7 +136,16 @@ def exp_locomo():
|
|
|
130
136
|
print(" refinement: 平均加条件数=%.2f 一步收敛率=%.1f%% (n=%d, %.0fs)"
|
|
131
137
|
% (steps_sum / max(n, 1), conv * 100.0 / max(n, 1), n,
|
|
132
138
|
time.time() - t0))
|
|
133
|
-
|
|
139
|
+
print(" false_accept(保守口径)=%.2f%% =G1 final top10 非 gold 平均占比"
|
|
140
|
+
"(上界:本语料无 CCG 注释面,非 gold 全计为假接受)"
|
|
141
|
+
% (fa10_sum * 10.0 / max(n, 1)))
|
|
142
|
+
print(" 候选池: G1 各阶段平均 top 池大小=%.1f (k=20 上限)"
|
|
143
|
+
% (sum(pool_sizes) / max(len(pool_sizes), 1)))
|
|
144
|
+
print(" 四态分布: 本实验为原子面(语料无 CCG 注释,judge_qualification "
|
|
145
|
+
"将全判 BLINDSPOT)——资格判定不适用,不硬造数字;四态实证见实验二")
|
|
146
|
+
return {"g0": st_g0, "g2": st_g2, "g1i": st_i, "g1f": st_f, "n": n,
|
|
147
|
+
"fa10_conservative": fa10_sum * 10.0 / max(n, 1),
|
|
148
|
+
"avg_pool": sum(pool_sizes) / max(len(pool_sizes), 1)}
|
|
134
149
|
|
|
135
150
|
|
|
136
151
|
def exp_controlled():
|
|
@@ -179,13 +194,32 @@ def exp_controlled():
|
|
|
179
194
|
out.append(nid)
|
|
180
195
|
return out
|
|
181
196
|
|
|
197
|
+
def state_dist(res):
|
|
198
|
+
"""渐进循环四态分布(top10 内 judge state 计数,只列非零项)。
|
|
199
|
+
|
|
200
|
+
judge info 直接复用 search_rrf(judge=True) 注入的
|
|
201
|
+
judge_qualification 产物(结果第三元),不重复判定。
|
|
202
|
+
"""
|
|
203
|
+
d = {"ACCEPT": 0, "DEFER": 0, "REJECT": 0, "BLINDSPOT": 0,
|
|
204
|
+
"无judge": 0}
|
|
205
|
+
for r in res[:10]:
|
|
206
|
+
st = (r[2] or {}).get("state") if len(r) > 2 else None
|
|
207
|
+
d[st if st in d else "无judge"] += 1
|
|
208
|
+
return {k: v for k, v in d.items() if v}
|
|
209
|
+
|
|
210
|
+
def fa_rate(res, fa):
|
|
211
|
+
return 100.0 * len(fa) / max(1, min(10, len(res)))
|
|
212
|
+
|
|
182
213
|
# 宽检索(不加任何条件;judgeinfo 直接取 results 第三元)
|
|
183
214
|
wide_res, _m = cg.search_rrf(QUERY, k=10, judge=True, **KW)
|
|
184
215
|
wide = [(r[0]["id"], r[1]) for r in wide_res]
|
|
185
216
|
fa_pre = false_accepts(wide_res)
|
|
186
217
|
top1_pre = wide[0][0] if wide else None
|
|
187
|
-
print(" 宽检索 top1=%s top10 内 False ACCEPT=%s"
|
|
188
|
-
% (top1_pre, fa_pre or "无"))
|
|
218
|
+
print(" 宽检索 top1=%s top10 内 False ACCEPT=%s(率=%.1f%%)"
|
|
219
|
+
% (top1_pre, fa_pre or "无", fa_rate(wide_res, fa_pre)))
|
|
220
|
+
print(" 四态分布(宽检索 top10)=%s 候选池=%d judge 剔除=%s"
|
|
221
|
+
% (state_dist(wide_res), len(wide_res),
|
|
222
|
+
(_m or {}).get("judge_filtered", 0)))
|
|
189
223
|
|
|
190
224
|
# 渐进:候选间区分性条件词 → 带条件重排
|
|
191
225
|
POOL = ["我", "喝水", "吃饭", "电脑", "书", "音乐", "出门",
|
|
@@ -203,7 +237,12 @@ def exp_controlled():
|
|
|
203
237
|
fa_post = false_accepts(refined_res)
|
|
204
238
|
top1_post = refined_res[0][0]["id"] if refined_res else None
|
|
205
239
|
print(" 区分性条件=%r → 重排 top1=%s top10 内 "
|
|
206
|
-
"False ACCEPT=%s"
|
|
240
|
+
"False ACCEPT=%s(率=%.1f%%)"
|
|
241
|
+
% (cond, top1_post, fa_post or "无",
|
|
242
|
+
fa_rate(refined_res, fa_post)))
|
|
243
|
+
print(" 四态分布(重排 top10)=%s 候选池=%d judge 剔除=%s"
|
|
244
|
+
% (state_dist(refined_res), len(refined_res),
|
|
245
|
+
(_m2 or {}).get("judge_filtered", 0)))
|
|
207
246
|
ok1 = top1_post in gold_ids
|
|
208
247
|
no_new = set(fa_post) <= set(fa_pre)
|
|
209
248
|
print(" 断言①渐进后 top1∈gold:%s" % ("PASS" if ok1 else "FAIL"))
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""记忆演化分支(Pi 机制移植④,交接文档 §3④「记忆演化 fork」,P0)。
|
|
3
|
+
|
|
4
|
+
pi:会话 = entry 树,任意历史节点可 fork;被放弃旁支由 branch_summary
|
|
5
|
+
归档定长摘要。灵枢映射(单一演化线 → 假设分支实验场):
|
|
6
|
+
|
|
7
|
+
- fork:把主支节点复制成分支实验副本(fm.branch_id / branched_from),
|
|
8
|
+
副本 derived_from=[主支]、relation="split_from"——血缘单向可回溯;
|
|
9
|
+
- 分支节点默认从主支检索隐身(_candidates 按 branch 过滤,一处生效
|
|
10
|
+
全链路穿透)——实验不污染主支(验收:召回主支时分支节点零命中);
|
|
11
|
+
- merge:按 branched_from 溯源回写主支(derived_from=[分支 nid] 追加进
|
|
12
|
+
主支原链、relation="merged_from"),override 走快照——合并后链完整;
|
|
13
|
+
- discard:校验 BRANCH_MARKS 必填 → 写教训节点(knowledge 层、可检索)
|
|
14
|
+
→ 分支文件移入冷区 _branches/<id>/(物理保留、索引摘除、永不删除)。
|
|
15
|
+
|
|
16
|
+
与 writepipe 同哲学:库层函数收 cg,权限闸保持库层强制——
|
|
17
|
+
fork/merge 走 add 的 require_layer_write 自动覆盖;
|
|
18
|
+
discard 改变库可见性,需 can_admin(principal.require_admin)。
|
|
19
|
+
生命周期事件走 _audit.jsonl(③ 两段式载体,零新日志格式)。
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import os
|
|
23
|
+
import re
|
|
24
|
+
import uuid
|
|
25
|
+
|
|
26
|
+
#: discard 的 branch_summary 必填标记(复用 NEG_MEMORY_MARKS 的必填防呆模式:
|
|
27
|
+
#: 「假设 + 结果 + 教训」缺一不收——放弃分支必须留下可复用的教训)。
|
|
28
|
+
BRANCH_MARKS = ("分支假设", "实验结果", "教训")
|
|
29
|
+
|
|
30
|
+
#: 分支文件冷区(LAYERS 之外,_scan_nodes 不扫——天然不进索引与检索)。
|
|
31
|
+
COLD_DIR = "_branches"
|
|
32
|
+
|
|
33
|
+
_BRANCH_RE = re.compile(r"^[a-z0-9][a-z0-9_-]{0,63}$")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def branch_tag(branch_id: str) -> str:
|
|
37
|
+
"""分支节点的标注 tag(fork 时写入;branch_summary 也带它以便反查)。"""
|
|
38
|
+
return "branch:" + str(branch_id or "").strip().lower()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def branch_node_id(orig: str, branch_id: str) -> str:
|
|
42
|
+
"""分支副本 id:`<主支nid>@<branch_id>`(@ 文件名合法、撞名不可能)。"""
|
|
43
|
+
return "%s@%s" % (orig, str(branch_id or "").strip().lower())
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _audit(cg, op: str, **meta) -> None:
|
|
47
|
+
"""生命周期留痕;审计失败绝不阻断主流程(G8 同哲学)。"""
|
|
48
|
+
a = getattr(cg, "_audit", None)
|
|
49
|
+
if a is None:
|
|
50
|
+
return
|
|
51
|
+
try:
|
|
52
|
+
a(op, None, **meta)
|
|
53
|
+
except Exception:
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _iter_branch_nodes(cg, branch_id: str):
|
|
58
|
+
bid = str(branch_id or "").strip().lower()
|
|
59
|
+
return [(k, v) for k, v in (cg.index.get("nodes") or {}).items()
|
|
60
|
+
if v.get("branch_id") == bid]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _fm_of(rec):
|
|
64
|
+
"""get 返回形态兼容:{'frontmatter': fm, 'content': c} 或平铺 fm。"""
|
|
65
|
+
if not rec:
|
|
66
|
+
return {}
|
|
67
|
+
return rec.get("frontmatter") or rec
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def fork(cg, node_ids, branch_id=None, note=None) -> dict:
|
|
71
|
+
"""把主支节点复制成分支实验副本。
|
|
72
|
+
|
|
73
|
+
返回 {ok, branch_id, tag, forked:[{from,to}], skipped:[{id,why}]}。
|
|
74
|
+
幂等:同 (主支节点, branch_id) 的副本已存在则 skipped,不重复复制。
|
|
75
|
+
"""
|
|
76
|
+
ids = [str(x).strip() for x in (node_ids or []) if str(x).strip()]
|
|
77
|
+
if not ids:
|
|
78
|
+
return {"ok": False, "error": "node_ids 为空(至少指定一个主支节点)"}
|
|
79
|
+
if branch_id is None:
|
|
80
|
+
branch_id = "br_" + uuid.uuid4().hex[:8]
|
|
81
|
+
branch_id = str(branch_id).strip().lower()
|
|
82
|
+
if not _BRANCH_RE.match(branch_id):
|
|
83
|
+
return {"ok": False, "error": "branch_id 非法(%s):%r"
|
|
84
|
+
% (_BRANCH_RE.pattern, branch_id)}
|
|
85
|
+
forked, skipped = [], []
|
|
86
|
+
for nid in ids:
|
|
87
|
+
if "@" in nid:
|
|
88
|
+
skipped.append({"id": nid, "why": "已是分支节点,不支持再 fork"})
|
|
89
|
+
continue
|
|
90
|
+
rec = cg.get(nid)
|
|
91
|
+
if not rec:
|
|
92
|
+
skipped.append({"id": nid, "why": "主支节点不存在或不可见"})
|
|
93
|
+
continue
|
|
94
|
+
fm = _fm_of(rec)
|
|
95
|
+
bid = branch_node_id(nid, branch_id)
|
|
96
|
+
if cg.get(bid):
|
|
97
|
+
skipped.append({"id": nid, "why": "副本已存在:%s" % bid})
|
|
98
|
+
continue
|
|
99
|
+
cg.add(bid, rec.get("content") or "",
|
|
100
|
+
layer=fm.get("layer") or "knowledge",
|
|
101
|
+
role=fm.get("role"),
|
|
102
|
+
tags=list(fm.get("tags") or []),
|
|
103
|
+
condition_space=fm.get("condition_space"),
|
|
104
|
+
importance=float(fm.get("importance", 0.5)),
|
|
105
|
+
verification_basis=fm.get("verification_basis") or "test",
|
|
106
|
+
non_applicable_conditions=fm.get("non_applicable_conditions"),
|
|
107
|
+
consistency=False,
|
|
108
|
+
derived_from=[nid], relation="split_from",
|
|
109
|
+
branch_id=branch_id, branched_from=nid, branch_note=note,
|
|
110
|
+
actor="branch_fork")
|
|
111
|
+
forked.append({"from": nid, "to": bid})
|
|
112
|
+
_audit(cg, "branch_fork", branch_id=branch_id,
|
|
113
|
+
forked=[f["to"] for f in forked])
|
|
114
|
+
return {"ok": bool(forked), "branch_id": branch_id,
|
|
115
|
+
"tag": branch_tag(branch_id), "forked": forked, "skipped": skipped}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def search(cg, query: str, branch_id: str, **kw):
|
|
119
|
+
"""分支内检索:主支 + 本分支可见、其他分支隐身(_candidates branch 过滤)。"""
|
|
120
|
+
return cg.search(query, branch=str(branch_id or "").strip().lower(), **kw)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def rewrite(cg, node_id, content, tags=None, importance=None,
|
|
124
|
+
actor="branch_rewrite", **extra) -> dict:
|
|
125
|
+
"""分支实验改写的**唯一正路**(防裸 add 丢分支归属)。
|
|
126
|
+
|
|
127
|
+
背景:add 是全量重建 fm——裸 add 改写分支节点而不重传 branch_id,
|
|
128
|
+
节点会在索引里退化成主支(实验内容直接泄漏进主支检索)。本帮手:
|
|
129
|
+
- 只接受在册分支节点(含 @ 且 entry.branch_id 在册);
|
|
130
|
+
- 归属与血缘(branch_id / branched_from / branch_note / derived_from /
|
|
131
|
+
derived_relation)一律从旧 fm 继承,调用方**不可改**(extra 里
|
|
132
|
+
同名键静默剥离)——「分支上怎么改内容都行,改不了它是谁的实验」;
|
|
133
|
+
- 层/条件空间/验证基底默认继承旧 fm(tags/importance 可显式覆盖);
|
|
134
|
+
- override=True → 旧内容自动快照留痕(③ 快照机制,零新日志)。
|
|
135
|
+
写权限由 add 的 require_layer_write 库层强制,不在此重复设闸。
|
|
136
|
+
"""
|
|
137
|
+
nid = str(node_id or "").strip()
|
|
138
|
+
if "@" not in nid:
|
|
139
|
+
return {"ok": False,
|
|
140
|
+
"error": "非分支节点(须为 <主支>@<branch_id> 形态):%s" % nid}
|
|
141
|
+
e = (cg.index.get("nodes") or {}).get(nid)
|
|
142
|
+
if not e or not e.get("branch_id"):
|
|
143
|
+
return {"ok": False, "error": "分支节点不存在或无分支归属:%s" % nid}
|
|
144
|
+
rec = cg.get(nid)
|
|
145
|
+
fm = _fm_of(rec)
|
|
146
|
+
if isinstance(content, dict) or content is None:
|
|
147
|
+
return {"ok": False, "error": "content 须为字符串"}
|
|
148
|
+
for k in ("branch_id", "branched_from", "branch_note", "derived_from",
|
|
149
|
+
"relation", "merged_from_branch", "override", "consistency"):
|
|
150
|
+
extra.pop(k, None) # 归属/血缘/写法闸不可经 extra 篡改
|
|
151
|
+
cg.add(nid, str(content or ""),
|
|
152
|
+
layer=fm.get("layer") or e.get("layer") or "knowledge",
|
|
153
|
+
tags=list(tags if tags is not None else (fm.get("tags") or [])),
|
|
154
|
+
importance=float(importance if importance is not None
|
|
155
|
+
else (fm.get("importance") or 0.5)),
|
|
156
|
+
condition_space=fm.get("condition_space"),
|
|
157
|
+
verification_basis=fm.get("verification_basis") or "test",
|
|
158
|
+
non_applicable_conditions=fm.get("non_applicable_conditions"),
|
|
159
|
+
override=True, consistency=False,
|
|
160
|
+
derived_from=list(fm.get("derived_from") or []),
|
|
161
|
+
relation=fm.get("derived_relation") or "split_from",
|
|
162
|
+
branch_id=fm.get("branch_id") or e.get("branch_id"),
|
|
163
|
+
branched_from=fm.get("branched_from") or e.get("branched_from"),
|
|
164
|
+
branch_note=fm.get("branch_note"),
|
|
165
|
+
actor=actor, **extra)
|
|
166
|
+
_audit(cg, "branch_rewrite", branch_id=e.get("branch_id"), node=nid)
|
|
167
|
+
return {"ok": True, "node": nid, "branch_id": e.get("branch_id")}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def merge(cg, branch_id, reason=None) -> dict:
|
|
171
|
+
"""把分支上的改写按 branched_from 溯源回写主支。
|
|
172
|
+
|
|
173
|
+
- 主支内容 = 分支内容;层/tags/重要性继承主支(实验元数据不带回去);
|
|
174
|
+
- 主支 derived_from 追加分支 nid(原链保留)、relation="merged_from";
|
|
175
|
+
- override=True → 主支旧内容自动快照留痕;
|
|
176
|
+
- 分支节点保留(merge 不自动删——显式两步、可逆、诚实)。
|
|
177
|
+
"""
|
|
178
|
+
bid = str(branch_id or "").strip().lower()
|
|
179
|
+
ents = _iter_branch_nodes(cg, bid)
|
|
180
|
+
if not ents:
|
|
181
|
+
return {"ok": False, "error": "分支不存在或无节点:%s" % bid}
|
|
182
|
+
merged, skipped = [], []
|
|
183
|
+
for nid, e in ents:
|
|
184
|
+
orig = e.get("branched_from")
|
|
185
|
+
rec = cg.get(orig) if orig else None
|
|
186
|
+
if not rec:
|
|
187
|
+
skipped.append({"id": nid, "why": "主支节点不存在:%s" % orig})
|
|
188
|
+
continue
|
|
189
|
+
src = cg.get(nid)
|
|
190
|
+
old_fm = _fm_of(rec)
|
|
191
|
+
src_fm = _fm_of(src)
|
|
192
|
+
chain = list(old_fm.get("derived_from") or [])
|
|
193
|
+
if nid not in chain:
|
|
194
|
+
chain.append(nid)
|
|
195
|
+
cg.add(orig, (src or {}).get("content") or "",
|
|
196
|
+
layer=old_fm.get("layer") or e.get("layer") or "knowledge",
|
|
197
|
+
tags=list(old_fm.get("tags") or e.get("tags") or []),
|
|
198
|
+
condition_space=src_fm.get("condition_space"),
|
|
199
|
+
importance=float(old_fm.get("importance", 0.5)),
|
|
200
|
+
verification_basis=old_fm.get("verification_basis") or "test",
|
|
201
|
+
non_applicable_conditions=old_fm.get("non_applicable_conditions"),
|
|
202
|
+
override=True, consistency=False,
|
|
203
|
+
derived_from=chain, relation="merged_from",
|
|
204
|
+
merged_from_branch=bid, actor="branch_merge")
|
|
205
|
+
merged.append({"branch_node": nid, "target": orig})
|
|
206
|
+
_audit(cg, "branch_merge", branch_id=bid,
|
|
207
|
+
merged=[m["target"] for m in merged], reason=reason)
|
|
208
|
+
return {"ok": bool(merged), "branch_id": bid, "merged": merged,
|
|
209
|
+
"skipped": skipped,
|
|
210
|
+
"hint": "分支节点保留:可 branch_search 继续实验,或 discard 冷归档"}
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def discard(cg, branch_id, summary: str) -> dict:
|
|
214
|
+
"""放弃分支:校验教训必填 → 写 branch_summary 教训节点 → 分支冷归档。
|
|
215
|
+
|
|
216
|
+
- summary 必须含 BRANCH_MARKS 三标记(缺一不收,防「无声放弃」);
|
|
217
|
+
- 教训节点进 knowledge 层、tags 带 branch:<id>——可被正常检索召回;
|
|
218
|
+
- 分支节点文件移入 _branches/<id>/(物理保留不违背永不删除,
|
|
219
|
+
LAYERS 之外故 _scan_nodes 不再扫到——索引与主支检索天然干净);
|
|
220
|
+
- 需 can_admin(改变库可见性属高危操作)。
|
|
221
|
+
"""
|
|
222
|
+
p = getattr(cg, "principal", None)
|
|
223
|
+
if p is not None:
|
|
224
|
+
p.require_admin("branch_discard")
|
|
225
|
+
bid = str(branch_id or "").strip().lower()
|
|
226
|
+
missing = [m for m in BRANCH_MARKS if m not in (summary or "")]
|
|
227
|
+
if missing:
|
|
228
|
+
return {"ok": False, "error": "branch_summary 缺必填标记",
|
|
229
|
+
"missing": missing, "required": list(BRANCH_MARKS)}
|
|
230
|
+
ents = _iter_branch_nodes(cg, bid)
|
|
231
|
+
if not ents:
|
|
232
|
+
return {"ok": False, "error": "分支不存在或无节点:%s" % bid}
|
|
233
|
+
body = summary if summary.lstrip().startswith("#") else \
|
|
234
|
+
"# branch_summary:%s\n\n%s" % (bid, summary)
|
|
235
|
+
sid = cg.add("branch_summary_%s" % bid, body, layer="knowledge",
|
|
236
|
+
tags=["branch_summary", branch_tag(bid)],
|
|
237
|
+
verification_basis="test", consistency=False,
|
|
238
|
+
actor="branch_discard")
|
|
239
|
+
cold = os.path.join(cg.root, COLD_DIR, bid)
|
|
240
|
+
os.makedirs(cold, exist_ok=True)
|
|
241
|
+
moved = 0
|
|
242
|
+
for nid, e in ents:
|
|
243
|
+
path = e.get("path")
|
|
244
|
+
if path:
|
|
245
|
+
src = os.path.join(cg.root, str(path).replace("/", os.sep))
|
|
246
|
+
if os.path.exists(src):
|
|
247
|
+
os.replace(src, os.path.join(cold, os.path.basename(src)))
|
|
248
|
+
moved += 1
|
|
249
|
+
(cg.index.get("nodes") or {}).pop(nid, None)
|
|
250
|
+
fl = getattr(cg, "flush", None)
|
|
251
|
+
if fl is not None:
|
|
252
|
+
try:
|
|
253
|
+
fl()
|
|
254
|
+
except Exception:
|
|
255
|
+
pass
|
|
256
|
+
_audit(cg, "branch_discard", branch_id=bid, moved=moved, summary_node=sid)
|
|
257
|
+
return {"ok": True, "branch_id": bid, "moved": moved,
|
|
258
|
+
"summary_node": sid, "cold_dir": "%s/%s" % (COLD_DIR, bid)}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def list_branches(cg) -> dict:
|
|
262
|
+
"""按 branch_id 聚合现存分支(节点清单 + 溯源主支)。"""
|
|
263
|
+
groups = {}
|
|
264
|
+
for nid, e in (cg.index.get("nodes") or {}).items():
|
|
265
|
+
bid = e.get("branch_id")
|
|
266
|
+
if not bid:
|
|
267
|
+
continue
|
|
268
|
+
g = groups.setdefault(bid, {"branch_id": bid, "tag": branch_tag(bid),
|
|
269
|
+
"nodes": [], "branched_from": []})
|
|
270
|
+
g["nodes"].append(nid)
|
|
271
|
+
bf = e.get("branched_from")
|
|
272
|
+
if bf and bf not in g["branched_from"]:
|
|
273
|
+
g["branched_from"].append(bf)
|
|
274
|
+
return {"ok": True,
|
|
275
|
+
"branches": sorted(groups.values(), key=lambda g: g["branch_id"])}
|