@furongjun1999/dsh-memory 0.4.8 → 0.4.10
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 +54 -26
- package/codebuddy/CODEBUDDY.md +196 -195
- 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/README.md +1 -1
- package/docs/discipline/harnesses.yaml +18 -7
- package/docs/discipline/templates/full.md.tmpl +4 -3
- 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/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/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/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.5.md +631 -625
- 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 +47 -45
- 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 → 206_v0.5.md} +92 -4
- 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//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/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 +2 -2
- 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//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 +2 -2
- 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 -433
- 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/dsh/README.md +33 -0
- 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 +3 -0
- package/lib/hooks.js +17 -23
- 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 +40 -3
- package/lib/lib/mdcg_client.js +46 -22
- package/lib/lib/mutual.js +4 -4
- package/lib/lib/token_store.js +4 -5
- package/md_cg/audit.py +17 -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 +27 -1
- package/md_cg/bench_p0.py +4 -1
- package/md_cg/bench_progressive.py +13 -1
- 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 +12 -1
- package/md_cg/build_postings.py +73 -0
- package/md_cg/ccgc.py +67 -2
- 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 +69 -4
- package/md_cg/consistency.py +24 -1
- package/md_cg/consolidate.py +53 -2
- package/md_cg/corpus.py +4 -0
- 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 +29 -1
- 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 +23 -1
- package/md_cg/fsutil.py +18 -1
- package/md_cg/hotcache.py +214 -0
- package/md_cg/hyperedge.py +251 -0
- package/md_cg/identity.py +18 -1
- package/md_cg/insight.py +17 -1
- 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 +12 -1
- package/md_cg/linkref.py +281 -0
- package/md_cg/links.py +29 -1
- package/md_cg/mcp_server.py +362 -43
- package/md_cg/md_whitebox.py +53 -1
- package/md_cg/mdcg.py +1003 -27
- package/md_cg/mdcos.py +558 -36
- package/md_cg/metacognition.py +37 -2
- 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/__main__.py +3 -0
- package/md_cg/mreview/bundle.py +8 -0
- package/md_cg/mreview/candidates.py +9 -0
- package/md_cg/mreview/govern.py +21 -1
- package/md_cg/mreview/locate.py +34 -0
- package/md_cg/mreview/pipeline.py +29 -1
- package/md_cg/mreview/ruleset.py +16 -1
- package/md_cg/nodefile.py +233 -3
- package/md_cg/pooling.py +23 -1
- package/md_cg/postings.py +298 -0
- package/md_cg/predict.py +89 -9
- package/md_cg/progressive.py +3 -0
- package/md_cg/protect.py +14 -1
- 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 +47 -2
- 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 +63 -2
- package/md_cg/security.py +26 -1
- package/md_cg/self_state.py +64 -1
- package/md_cg/selfreport.py +151 -0
- package/md_cg/semantic/canonical.py +5 -0
- package/md_cg/semantic/en_normalizer.py +364 -355
- 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 +56 -1
- package/md_cg/tasks.py +26 -2
- 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_ccgc.py +10 -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_d_meta.py +412 -0
- package/md_cg/test_datapath_root.py +188 -0
- package/md_cg/test_gain_gate.py +47 -1
- package/md_cg/test_hot_cold.py +187 -0
- package/md_cg/test_hyperedge.py +245 -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 +108 -18
- package/md_cg/test_mr_m3.py +8 -1
- package/md_cg/test_p26_refindex.py +49 -20
- package/md_cg/test_p27_docindex.py +236 -2
- package/md_cg/test_p2_mcp.py +1 -1
- package/md_cg/test_p31_insight.py +24 -0
- 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 +8 -4
- 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 +59 -2
- package/md_cg/test_role_views.py +354 -0
- package/md_cg/test_subproc_encoding.py +188 -0
- package/md_cg/test_trust.py +361 -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 +5 -1
- package/md_cg/theory.py +16 -1
- package/md_cg/tokens.py +40 -8
- package/md_cg/tool_face.py +13 -2
- package/md_cg/trust.py +943 -0
- package/md_cg/twophase.py +12 -1
- package/md_cg/units.py +132 -10
- package/md_cg/vision_evidence.py +24 -1
- package/md_cg/weights.py +24 -1
- package/md_cg/whitebox.py +32 -1
- package/md_cg/whitebox_kb/data/verify_cache.json +21210 -365
- package/md_cg/whitebox_kb/data/verify_savings.jsonl +5078 -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 +18 -4
- package/md_cg/writepipe.py +178 -7
- 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 +17 -21
- package/src/index.ts +33 -6
- package/src/lib/datapath.ts +211 -13
- package/src/lib/mdcg_client.ts +64 -25
- package/src/lib/mutual.ts +411 -411
- package/src/lib/token_store.ts +4 -5
- package/zcode/AGENTS.md +196 -195
- package/zcode/README.md +4 -0
- 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/autonomy.py
CHANGED
|
@@ -26,13 +26,24 @@ import json
|
|
|
26
26
|
import os
|
|
27
27
|
import time
|
|
28
28
|
|
|
29
|
-
from . import metacognition, predict
|
|
29
|
+
from . import d_meta, metacognition, predict
|
|
30
30
|
from .fsutil import append_jsonl
|
|
31
31
|
|
|
32
32
|
#: 信息差评分权重:不确定度二阶差分 |d2|(加速度)×1,
|
|
33
33
|
#: BLINDSPOT ×2(资格失败最重)、DEFER ×1(降级但可确认)。
|
|
34
34
|
W_D2, W_BLINDSPOT, W_DEFER = 1.0, 2.0, 1.0
|
|
35
35
|
|
|
36
|
+
#: D_meta 排序加分(方案 §2.4,**默认生效**):D_meta 只进**排序键**,
|
|
37
|
+
#: 不改 `score`(ΔD 定价器口径不变)、不改资格判据(score>0 才是资格)、
|
|
38
|
+
#: 也不改 σ(Gain) 筛选(#37 价值链)。加分取**单一指定代理**(DMETA_PROXY),
|
|
39
|
+
#: 禁三代理加权合成(智能论3.4 DEV-002a)。`MDCG_D_META=0` → compute()
|
|
40
|
+
#: 返回 enabled=False → 加分退化 0(回到旧排序)。
|
|
41
|
+
#: 口径诚实标注:本轮取库侧 query 无关代理 → 同轮全部提案加分同值 → **当前
|
|
42
|
+
#: 口径下排序不变**;区分性待 query-relative 口径(`_neg_coverage`)在
|
|
43
|
+
#: reflect 侧落盘后自然生效(不提前编造区分性)。
|
|
44
|
+
W_DMETA = 0.1
|
|
45
|
+
DMETA_PROXY = "unmodeled_growth"
|
|
46
|
+
|
|
36
47
|
EXPLORE_LOG = "_explore.jsonl"
|
|
37
48
|
|
|
38
49
|
# P-T-40 信息增益门槛(#6/#37 投影):Value = ΔD·σ(Gain)——
|
|
@@ -44,10 +55,12 @@ GAIN_COOLDOWN = 3600.0 # 冷却秒数:过期后 σ 回 1.0(给探索机会
|
|
|
44
55
|
_GAIN_STUCK = ("carried", "unresolved", "unknowable", "no_anchor")
|
|
45
56
|
|
|
46
57
|
|
|
58
|
+
# 生效条件:cg 无 root 属性时以 '.' 作为 os.path.join 的第一参数,有 root 属性时始终使用 cg.root 的值(即使为 None,也会传入 os.path.join 导致报错),再与模块常量 EXPLORE_LOG 拼接。
|
|
47
59
|
def _explore_log_path(cg):
|
|
48
60
|
return os.path.join(getattr(cg, "root", "."), EXPLORE_LOG)
|
|
49
61
|
|
|
50
62
|
|
|
63
|
+
# 生效条件:给定 cg 与 bid 读取探索留痕,无该 bid 的 outcomes 时返回 gain=None、sigma=1.0,最近 window(默认 GAIN_WINDOW)次终态全属 _GAIN_STUCK 且 now-last_t 小于 cooldown(默认 GAIN_COOLDOWN)时返回 sigma=0.0、gain=0,终态全属 _GAIN_STUCK 但冷却已过、且与该 bid 相关轮次的 meta_outcomes.delta[DMETA_PROXY] 均值大于 0 时同样返回 sigma=0.0、gain=0(压力仍在扩大则不放行),其余返回 sigma=1.0、gain=1;meta_outcomes 键缺失、delta 非字典或其值为非数值的轮次不计入压力均值(缺键即不触发新分支,既有 ①-④ 行为逐字不变)。
|
|
51
64
|
def gain_gate(cg, bid: str, now: float | None = None,
|
|
52
65
|
window: int = GAIN_WINDOW, cooldown: float = GAIN_COOLDOWN) -> dict:
|
|
53
66
|
"""信息增益门槛(P-T-40 第四保护投影,纯读无副作用)。
|
|
@@ -61,7 +74,7 @@ def gain_gate(cg, bid: str, now: float | None = None,
|
|
|
61
74
|
`now` 可注入以便测试冷却过期。
|
|
62
75
|
"""
|
|
63
76
|
now = time.time() if now is None else float(now)
|
|
64
|
-
terminals, last_t = [], 0.0
|
|
77
|
+
terminals, last_t, meta_deltas = [], 0.0, []
|
|
65
78
|
try:
|
|
66
79
|
with open(_explore_log_path(cg), encoding="utf-8") as f:
|
|
67
80
|
for line in f:
|
|
@@ -75,30 +88,58 @@ def gain_gate(cg, bid: str, now: float | None = None,
|
|
|
75
88
|
if bid in oc:
|
|
76
89
|
terminals.append(str(oc[bid]))
|
|
77
90
|
last_t = max(last_t, float(r.get("t") or 0.0))
|
|
91
|
+
# D_meta 跨轮压力增量(缺键/关闭 → 不计入 → 不触发新分支)
|
|
92
|
+
mo = r.get("meta_outcomes")
|
|
93
|
+
dlt = mo.get("delta") if isinstance(mo, dict) else None
|
|
94
|
+
v = dlt.get(DMETA_PROXY) if isinstance(dlt, dict) else None
|
|
95
|
+
if isinstance(v, (int, float)) and not isinstance(v, bool):
|
|
96
|
+
meta_deltas.append(float(v))
|
|
78
97
|
except OSError:
|
|
79
98
|
pass
|
|
80
99
|
if not terminals:
|
|
81
100
|
return {"sigma": 1.0, "gain": None, "last_t": 0.0,
|
|
82
101
|
"reason": "无探索历史(首探放行:无证据不否决)"}
|
|
83
102
|
recent = terminals[-int(window):]
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
103
|
+
stuck = (len(recent) >= int(window)
|
|
104
|
+
and all(t in _GAIN_STUCK for t in recent))
|
|
105
|
+
rising = bool(meta_deltas) and (sum(meta_deltas) / len(meta_deltas)) > 0
|
|
106
|
+
meta_txt = ""
|
|
107
|
+
if rising:
|
|
108
|
+
meta_txt = (";D_meta 压力均值 %+.4f(%s,近 %d 轮留痕)"
|
|
109
|
+
% (sum(meta_deltas) / len(meta_deltas), DMETA_PROXY,
|
|
110
|
+
len(meta_deltas)))
|
|
111
|
+
if stuck and (now - last_t) < float(cooldown):
|
|
87
112
|
return {"sigma": 0.0, "gain": 0, "last_t": round(last_t, 3),
|
|
88
113
|
"reason": ("增益门槛(P-T-40):连续 %d 次终态无变化 %s → "
|
|
89
|
-
"DEFER_EXHAUSTED(冷却 %ds
|
|
90
|
-
% (len(recent), list(recent), int(cooldown)
|
|
114
|
+
"DEFER_EXHAUSTED(冷却 %ds 内不再重复探索)%s"
|
|
115
|
+
% (len(recent), list(recent), int(cooldown),
|
|
116
|
+
meta_txt))}
|
|
117
|
+
if stuck and rising:
|
|
118
|
+
return {"sigma": 0.0, "gain": 0, "last_t": round(last_t, 3),
|
|
119
|
+
"meta_rising": True,
|
|
120
|
+
"reason": ("增益门槛(P-T-40):连续 %d 次终态无变化 %s 且 "
|
|
121
|
+
"D_meta 压力仍在扩大%s → "
|
|
122
|
+
"DEFER_EXHAUSTED_UNDER_PRESSURE(冷却已过但不放行:"
|
|
123
|
+
"压力扩大而终态停滞 = 重复探索不再产生增益)"
|
|
124
|
+
% (len(recent), list(recent), meta_txt))}
|
|
91
125
|
return {"sigma": 1.0, "gain": 1, "last_t": round(last_t, 3),
|
|
92
126
|
"reason": "有增益证据或冷却已过"}
|
|
93
127
|
|
|
94
128
|
|
|
129
|
+
# 生效条件:cg 的反思记录经 metacognition._reflections 取末 int(window) 条切片(window=0 时切片即全量),按非空 query 聚合后仅 score=W_D2*d2_abs+W_BLINDSPOT*blindspot+W_DEFER*defer>0 的项进入 out(**资格判据先于加分**:score<=0 即 continue,D_meta 不构成资格),其中 enforce_gain 为真值时还须 gain_gate(cg, …, now)["sigma"]>0 否则该项标 deferred_exhausted 转入 deferred,enforce_gain 为假值时不做增益筛选全数进入 out;D_meta 加分 W_DMETA*d_meta.pressure(d_meta.compute(cg, window), DMETA_PROXY) 每轮只算一次并在循环内复用,只写入 sort_score 与 reason 证据(不改 score、不改资格、不改 σ),MDCG_D_META 关闭或未启用时该加分为 0.0;最终 out 按 (-sort_score, -last_t) 排序后截取 max(1, int(limit)) 条(limit=0 或负数也返回 1 条)并随 n_signals=len(agg) 返回;
|
|
95
130
|
def proposals(cg, window: int = 200, limit: int = 3,
|
|
96
131
|
enforce_gain: bool = True) -> dict:
|
|
97
132
|
"""从反思日志聚合信息差信号,产出排序后的探索提案。
|
|
98
133
|
|
|
99
134
|
每条提案携带证据明细(d2 之和/绝对值和、BLINDSPOT/DEFER 计数、样本数),
|
|
100
|
-
|
|
101
|
-
|
|
135
|
+
`score` = W_D2*Σ|d2| + W_BLINDSPOT*BLINDSPOT + W_DEFER*DEFER(**ΔD 定价器,
|
|
136
|
+
口径不变**);`sort_score` = score + W_DMETA×D_meta 边界压力(排序键)。
|
|
137
|
+
无信号的查询不产生提案(不编造探索价值)——**D_meta 加分不构成资格**:
|
|
138
|
+
`score<=0` 的项在加分之前就被 continue 掉。
|
|
139
|
+
|
|
140
|
+
D_meta 只影响**排序**、不改 σ(Gain) 筛选;本轮取库侧 query 无关的单一
|
|
141
|
+
代理(DMETA_PROXY),同轮各提案加分同值,故当前口径下排序不变——
|
|
142
|
+
区分性待 query-relative 口径落盘后自然生效(不提前编造)。
|
|
102
143
|
|
|
103
144
|
`enforce_gain`(默认 True):σ(Gain) 资格筛选(#37 价值链——score 是
|
|
104
145
|
定价器,Gain 是筛选器)。被门槛拦下的提案不静默丢弃,落入 `deferred`
|
|
@@ -129,17 +170,24 @@ def proposals(cg, window: int = 200, limit: int = 3,
|
|
|
129
170
|
|
|
130
171
|
out, deferred = [], []
|
|
131
172
|
now = time.time()
|
|
173
|
+
mv = d_meta.compute(cg, window=window) # 每轮一次、循环内复用(禁 N× 扫描)
|
|
174
|
+
bonus = (round(W_DMETA * d_meta.pressure(mv, DMETA_PROXY), 4)
|
|
175
|
+
if mv.get("enabled") else 0.0)
|
|
132
176
|
for a in agg.values():
|
|
133
177
|
score = (W_D2 * a["d2_abs"] + W_BLINDSPOT * a["blindspot"]
|
|
134
178
|
+ W_DEFER * a["defer"])
|
|
135
179
|
if score <= 0:
|
|
136
180
|
continue # 无信息差信号 → 不提案(不编造)
|
|
137
181
|
a = dict(a)
|
|
138
|
-
a["score"] = round(score, 4)
|
|
182
|
+
a["score"] = round(score, 4) # ΔD 定价器:口径不变
|
|
183
|
+
a["d_meta_bonus"] = bonus # D_meta 排序加分(只影响排序)
|
|
184
|
+
a["sort_score"] = round(score + bonus, 4)
|
|
139
185
|
a["reason"] = ("信息差信号:Σ|d2|=%s(Σd2=%s)+ BLINDSPOT×%d + DEFER×%d"
|
|
140
|
-
"(近 %d
|
|
186
|
+
"(近 %d 次反思);D_meta 排序加分 +%s(%s=%s,三代理"
|
|
187
|
+
"不合成;不改资格/σ(Gain))"
|
|
141
188
|
% (a["d2_abs"], a["d2_sum"], a["blindspot"],
|
|
142
|
-
a["defer"], a["samples"]
|
|
189
|
+
a["defer"], a["samples"], bonus, DMETA_PROXY,
|
|
190
|
+
d_meta.pressure(mv, DMETA_PROXY)))
|
|
143
191
|
if enforce_gain: # P-T-40 增益门槛:资格由实现值裁决
|
|
144
192
|
gate = gain_gate(cg, metacognition._key(a["query"]), now=now)
|
|
145
193
|
a["gain_gate"] = gate
|
|
@@ -148,13 +196,17 @@ def proposals(cg, window: int = 200, limit: int = 3,
|
|
|
148
196
|
deferred.append(a)
|
|
149
197
|
continue
|
|
150
198
|
out.append(a)
|
|
151
|
-
out.sort(key=lambda x: (-x["
|
|
199
|
+
out.sort(key=lambda x: (-x["sort_score"], -x["last_t"]))
|
|
152
200
|
return {"ok": True, "proposals": out[:max(1, int(limit))],
|
|
153
201
|
"n_signals": len(agg), "deferred": deferred,
|
|
202
|
+
"d_meta": {"enabled": bool(mv.get("enabled")), "bonus": bonus,
|
|
203
|
+
"proxy": DMETA_PROXY},
|
|
154
204
|
"value_chain": ("Value=ΔD·σ(Gain):score 定价排序(ΔD 代理),"
|
|
155
|
-
"σ(Gain) 资格筛选(实现值=outcomes
|
|
205
|
+
"σ(Gain) 资格筛选(实现值=outcomes 留痕);"
|
|
206
|
+
"D_meta 只加排序分、不改资格(DEV-002a)")}
|
|
156
207
|
|
|
157
208
|
|
|
209
|
+
# 生效条件:cg 必需,该符号始终返回 ok=True、action="explore";其中 bypass_gain 为真值时以 enforce_gain=False 调 proposals、为假值时以 True 调(window/limit 原样透传),逐条提案用 apply/actor 调 predict.learn_blindspots 并把其首个 step 的 terminal 记入 outcomes[bid],同一 blindspot_id 本轮已见则记为 skipped,调用抛异常则记为 error("%s: %s" % (type(exc).__name__, exc)),并额外取本轮 d_meta.compute(append 前状态)与上一条 explore 留痕的 meta_outcomes.before,并列写入 meta_outcomes={before, prev_before, delta, proxy, enabled}(**outcomes 值类型不变**),最后 append_jsonl 写 _explore_log_path(cg) 时仅 OSError 被忽略;
|
|
158
210
|
def explore(cg, apply: bool = False, limit: int = 3, window: int = 200,
|
|
159
211
|
actor: str = "autonomy", bypass_gain: bool = False) -> dict:
|
|
160
212
|
"""最小探索闭环:提案 → 逐盲区五态验证 →(apply)回写待补线索。
|
|
@@ -173,6 +225,11 @@ def explore(cg, apply: bool = False, limit: int = 3, window: int = 200,
|
|
|
173
225
|
(绕过增益筛选照常探索,留痕 bypass_gain 字段可审计)。
|
|
174
226
|
"""
|
|
175
227
|
pr = proposals(cg, window=window, limit=limit, enforce_gain=not bypass_gain)
|
|
228
|
+
mv = d_meta.compute(cg, window=window) # 本轮 D_meta(append 前状态)
|
|
229
|
+
prev = None
|
|
230
|
+
for r in d_meta.tail_jsonl(_explore_log_path(cg), 1):
|
|
231
|
+
mo = r.get("meta_outcomes") if isinstance(r, dict) else None
|
|
232
|
+
prev = mo.get("before") if isinstance(mo, dict) else None
|
|
176
233
|
steps, outcomes, seen = [], {}, set()
|
|
177
234
|
for p in pr["proposals"]:
|
|
178
235
|
bid = metacognition._key(p["query"])
|
|
@@ -201,6 +258,20 @@ def explore(cg, apply: bool = False, limit: int = 3, window: int = 200,
|
|
|
201
258
|
"bids": [s["blindspot_id"] for s in steps],
|
|
202
259
|
"outcomes": outcomes,
|
|
203
260
|
"bypass_gain": bool(bypass_gain),
|
|
261
|
+
# D_meta 并列留痕(**outcomes 值类型不变**:终态字符串契约是
|
|
262
|
+
# gain_gate 停滞集比对的前提,改成 dict 会让 σ 静默恒为 1.0):
|
|
263
|
+
# before = 本轮开始时的三代理(含上轮 apply 的效果)
|
|
264
|
+
# prev_before = 上一条 explore 留痕的 before(无则 None)
|
|
265
|
+
# delta = before − prev_before(跨轮压力增量 → gain_gate 输入)
|
|
266
|
+
"meta_outcomes": {
|
|
267
|
+
"before": {k: float(mv.get(k) or 0.0)
|
|
268
|
+
for k in d_meta.PROXY_KEYS},
|
|
269
|
+
"prev_before": ({k: float(prev.get(k) or 0.0)
|
|
270
|
+
for k in d_meta.PROXY_KEYS}
|
|
271
|
+
if isinstance(prev, dict) else None),
|
|
272
|
+
"delta": d_meta.diff(prev, mv),
|
|
273
|
+
"proxy": DMETA_PROXY,
|
|
274
|
+
"enabled": bool(mv.get("enabled"))},
|
|
204
275
|
"gain_deferred": [(d.get("query"), d.get("gain_gate", {}).get("reason"))
|
|
205
276
|
for d in (pr.get("deferred") or [])]}
|
|
206
277
|
try:
|
|
@@ -214,4 +285,4 @@ def explore(cg, apply: bool = False, limit: int = 3, window: int = 200,
|
|
|
214
285
|
"裁决资格);终态五态由 learn_blindspots 诚实判定;"
|
|
215
286
|
"apply=True 仅落地 carried/unresolved 的 gap_hint 待补"
|
|
216
287
|
"线索(幂等);P-T-40 四保护=单轮深度/本轮循环去重/"
|
|
217
|
-
"增益冷却/预算 limit(bypass_gain 显式豁免可审计)")}
|
|
288
|
+
"增益冷却/预算 limit(bypass_gain 显式豁免可审计)")}
|
package/md_cg/backfill.py
CHANGED
|
@@ -127,11 +127,13 @@ CAP_RULES = OrderedDict(
|
|
|
127
127
|
|
|
128
128
|
# ---- 通用工具 ------------------------------------------------------------
|
|
129
129
|
|
|
130
|
+
# 生效条件:x 为 str 时返回 MdCGOS(x),否则原样返回 x。
|
|
130
131
|
def _as_cg(x):
|
|
131
132
|
"""接受 root 路径或已构造的 cg 实例——保持密级隔离与密钥上下文。"""
|
|
132
133
|
return MdCGOS(x) if isinstance(x, str) else x
|
|
133
134
|
|
|
134
135
|
|
|
136
|
+
# 生效条件:v 为 list/tuple 时返回分号连接的非空元素文本;v 为 None 或空串时返回 "";否则返回 str(v).strip()(v 为 0 或 False 走此支返回 "0"/"False")。
|
|
135
137
|
def _as_text(v) -> str:
|
|
136
138
|
if isinstance(v, (list, tuple)):
|
|
137
139
|
return ";".join(str(x).strip() for x in v if str(x).strip())
|
|
@@ -140,12 +142,14 @@ def _as_text(v) -> str:
|
|
|
140
142
|
return str(v).strip()
|
|
141
143
|
|
|
142
144
|
|
|
145
|
+
# 生效条件:fm 为假值时按 {} 处理,state_attributes.comment 为 dict 时返回该 dict,否则返回 {}。
|
|
143
146
|
def _comment(fm: dict) -> dict:
|
|
144
147
|
st = (fm or {}).get("state_attributes")
|
|
145
148
|
c = st.get("comment") if isinstance(st, dict) else None
|
|
146
149
|
return c if isinstance(c, dict) else {}
|
|
147
150
|
|
|
148
151
|
|
|
152
|
+
# 生效条件:fm 的 state_attributes 为 dict 且其下 comment 为 dict 时原样返回该 comment;否则创建并返回空 comment dict(state_attributes 非 dict 时置 fm["state_attributes"]={},comment 非 dict 时置 st["comment"]={})。
|
|
149
153
|
def _ensure_comment(fm: dict) -> dict:
|
|
150
154
|
st = fm.get("state_attributes")
|
|
151
155
|
if not isinstance(st, dict):
|
|
@@ -158,10 +162,12 @@ def _ensure_comment(fm: dict) -> dict:
|
|
|
158
162
|
return c
|
|
159
163
|
|
|
160
164
|
|
|
165
|
+
# 生效条件:e 的 id 为真值时返回 id,否则返回 e 的 path 基名去掉最后 3 个字符(path 为假值时基名为空,结果空串)。
|
|
161
166
|
def _node_id(e: dict) -> str:
|
|
162
167
|
return e.get("id") or os.path.basename(e.get("path") or "")[:-3]
|
|
163
168
|
|
|
164
169
|
|
|
170
|
+
# 生效条件:fm 的 condition_space 四槽齐全时返回 nodefile.condition_space_text 合成文本,否则返回空串。
|
|
165
171
|
def _condition_text(fm: dict) -> str:
|
|
166
172
|
"""→ 条件空间四槽合成的生效条件声明;四槽不齐 → ""(不冒充)。
|
|
167
173
|
|
|
@@ -172,14 +178,17 @@ def _condition_text(fm: dict) -> str:
|
|
|
172
178
|
return nodefile.condition_space_text((fm or {}).get("condition_space"))
|
|
173
179
|
|
|
174
180
|
|
|
181
|
+
# 生效条件:s 为真值时返回其 sha1 前 12 位,s 为假值(None/空串等)时对空串取 sha1 前 12 位。
|
|
175
182
|
def _sha(s: str) -> str:
|
|
176
183
|
return hashlib.sha1((s or "").encode("utf-8")).hexdigest()[:12]
|
|
177
184
|
|
|
178
185
|
|
|
186
|
+
# 生效条件:batch 与 nid 经 f-string 拼接后取 sha1 前 12 位;两者为 None 会字符串化为 "None"。
|
|
179
187
|
def _entry_id(batch: str, nid: str) -> str:
|
|
180
188
|
return hashlib.sha1(f"{batch}|{nid}".encode("utf-8")).hexdigest()[:12]
|
|
181
189
|
|
|
182
190
|
|
|
191
|
+
# 生效条件:content 中 strip 后以 # 开头且去掉 # 与空白后、全角或半角冒号前首段等于 field 的整行被删除,其余行保留并 join。
|
|
183
192
|
def _remove_ccg_line(content: str, field: str) -> str:
|
|
184
193
|
"""删掉 `# <字段>:…` 整行(回滚用)。"""
|
|
185
194
|
keep = []
|
|
@@ -192,12 +201,14 @@ def _remove_ccg_line(content: str, field: str) -> str:
|
|
|
192
201
|
return "\n".join(keep)
|
|
193
202
|
|
|
194
203
|
|
|
204
|
+
# 生效条件:cg.root 与模块级常量 BACKFILL_LOG 拼接为返回路径。
|
|
195
205
|
def _log_path(cg) -> str:
|
|
196
206
|
return os.path.join(cg.root, BACKFILL_LOG)
|
|
197
207
|
|
|
198
208
|
|
|
199
209
|
# ---- 字段推导(唯一入口:只搬运已声明的证据) -----------------------------
|
|
200
210
|
|
|
211
|
+
# 生效条件:fm 与 content 给定时,仅对 content 中尚无对应 CCG 行的字段(功能名/生效条件/子功能/执行/验证方式/不适用条件)从 fm 的已有声明(state_attributes.comment、frontmatter、verification_basis、或形参 basis_text)取值,值非空且非占位文本才写入 out,假值不写、占位文本只把字段名追加进 placeholder_out(未传该形参时用临时列表)。
|
|
201
212
|
def derive_fields(fm: dict, content: str, basis_text: str = None,
|
|
202
213
|
placeholder_out: list = None) -> dict:
|
|
203
214
|
"""按**已有声明**推导可回填字段 → `{field: (value, basis)}`。
|
|
@@ -213,6 +224,7 @@ def derive_fields(fm: dict, content: str, basis_text: str = None,
|
|
|
213
224
|
ph = placeholder_out if placeholder_out is not None else []
|
|
214
225
|
out = {}
|
|
215
226
|
|
|
227
|
+
# 生效条件:field 与 basis 在 value 为真值且 nodefile.is_placeholder_text(value) 为假时写入 out;value 为假值不写入;value 为占位文本时仅把 field 记入 ph。
|
|
216
228
|
def _put(field, value, basis):
|
|
217
229
|
"""有值且非占位标记才写出;占位值只记名,绝不渲染成事实。"""
|
|
218
230
|
if not value:
|
|
@@ -267,6 +279,7 @@ def derive_fields(fm: dict, content: str, basis_text: str = None,
|
|
|
267
279
|
|
|
268
280
|
# ---- 节点筛选 ------------------------------------------------------------
|
|
269
281
|
|
|
282
|
+
# 生效条件:cg 无 _readable 可调用时返回 True;有可调用时返回 bool(fn(e)),fn(e) 抛异常时返回 False。
|
|
270
283
|
def _readable_guard(cg, e) -> bool:
|
|
271
284
|
fn = getattr(cg, "_readable", None)
|
|
272
285
|
if not callable(fn):
|
|
@@ -277,6 +290,7 @@ def _readable_guard(cg, e) -> bool:
|
|
|
277
290
|
return False
|
|
278
291
|
|
|
279
292
|
|
|
293
|
+
# 生效条件:仅当 cg 对 e 读出的 fm 非 None、content 未被 crypto.is_encrypted、e['layer'] 不在 SKIP_LAYERS 且 fm.get('tags') 无命中 SKIP_TAGS、ccg_completeness(content)['complete'] 为假时才继续——derive_fields(受 basis_text 影响)过滤掉 content 已有 CCG 行的可写字段为空时按 placeholder_out 是否非空返回 ('placeholder'/'unfillable', None),非空时返回 ('', item)(item 的 id 取 nid、class 依 undeducible 是否为空取 'backfillable' 或 'partial');上述四个前置不满足时依次返回 ('unreadable'/'locked'/'derived'/'present', None)。
|
|
280
294
|
def _classify(cg, e, nid, basis_text=None):
|
|
281
295
|
"""→ (skip_reason, item);skip_reason 非空表示不参与回填。"""
|
|
282
296
|
fm, content = cg._read(e)
|
|
@@ -317,6 +331,7 @@ def _classify(cg, e, nid, basis_text=None):
|
|
|
317
331
|
}
|
|
318
332
|
|
|
319
333
|
|
|
334
|
+
# 生效条件:x 经 _as_cg 后遍历 cg.index.nodes,按 ids/layer/prefix 过滤,内部层/不可读/locked/derived/present/unfillable/placeholder/partial 且 include_partial 为 False 分别计数跳过,其余标记 entry_id 并计入 targeted,items 受 limit 限制(limit 为 None 或 len(items) < limit 时追加),返回 dry_run rep。
|
|
320
335
|
def plan(x, layer=None, limit=None, ids=None, include_partial=False,
|
|
321
336
|
basis_text=None, prefix=None) -> dict:
|
|
322
337
|
"""预演:产出可回填清单,不写盘。
|
|
@@ -381,6 +396,7 @@ def plan(x, layer=None, limit=None, ids=None, include_partial=False,
|
|
|
381
396
|
|
|
382
397
|
# ---- 回填写入 / 回滚 / 留痕 ----------------------------------------------
|
|
383
398
|
|
|
399
|
+
# 生效条件:x 可被 _as_cg 解释为 CG 句柄时,按 layer/ids/prefix/entry_ids 选定条目做回填并返回含 written 等计数的 rep,其中 limit 非 None 时把写入数截断到该值。
|
|
384
400
|
def apply(x, ids=None, entry_ids=None, layer=None, limit=None,
|
|
385
401
|
batch=BATCH_DEFAULT, include_partial=False, basis_text=None,
|
|
386
402
|
actor=None, prefix=None) -> dict:
|
|
@@ -458,6 +474,7 @@ def apply(x, ids=None, entry_ids=None, layer=None, limit=None,
|
|
|
458
474
|
return rep
|
|
459
475
|
|
|
460
476
|
|
|
477
|
+
# 生效条件:x 经 _as_cg 定位后读留痕日志,仅对 action=='backfill' 且(batch 为假值则不过滤 batch,否则 rec['batch']==batch)、(entry_ids 为假值则不过滤,否则 rec['entry_id'] 属于该集合)、write_id 未出现在已完成 rollback 集合中、节点命中 cg.index['nodes'] 且 cg._read(e) 的 fm 可读、字段当前 _ccg_field(content, f) 等于留痕 after 的记录执行撤销写回(before 为 None 则删该 comment 键,否则还原原值),无字段可撤销只计 conflict 不写盘,reverted 非空时 rebuild_index,结果汇总进返回的 rep。
|
|
461
478
|
def rollback(x, batch=None, entry_ids=None, actor=None) -> dict:
|
|
462
479
|
"""按留痕反向应用:撤销本批次回填(当前值 ≠ 写入值时跳过,防覆盖)。"""
|
|
463
480
|
cg = _as_cg(x)
|
|
@@ -528,6 +545,7 @@ def rollback(x, batch=None, entry_ids=None, actor=None) -> dict:
|
|
|
528
545
|
return rep
|
|
529
546
|
|
|
530
547
|
|
|
548
|
+
# 生效条件:x 经 _as_cg,action/batch 为真值时过滤对应日志记录;limit 不为 None 且 >=0 时按 recs[-limit:] 截断(limit=0 时切片为全部记录),limit 为 None 或负数时不截断;返回 total/returned/records。
|
|
531
549
|
def history(x, limit=100, action=None, batch=None) -> dict:
|
|
532
550
|
cg = _as_cg(x)
|
|
533
551
|
recs = []
|
|
@@ -555,6 +573,7 @@ def history(x, limit=100, action=None, batch=None) -> dict:
|
|
|
555
573
|
_CAP_TEMPLATE_LINES = ("验证方式",)
|
|
556
574
|
|
|
557
575
|
|
|
576
|
+
# 生效条件:content 中去除 # 与空白后、全角或半角冒号前首段命中 _CAP_TEMPLATE_LINES 的行被剔除,其余行保留并 join。
|
|
558
577
|
def _cap_body(content: str) -> str:
|
|
559
578
|
"""正文(供关键词匹配)——剔除 CCG 模板行,防模板词污染候选。"""
|
|
560
579
|
keep = []
|
|
@@ -567,6 +586,7 @@ def _cap_body(content: str) -> str:
|
|
|
567
586
|
return "\n".join(keep)
|
|
568
587
|
|
|
569
588
|
|
|
589
|
+
# 生效条件:当 fm 为可 get 的 frontmatter、e 为带 id 的节点条目、content 为正文文本时,返回 title+e.id+功能名/生效条件/子功能字段+正文前 300 字合并后的小写串(不含 fm.tags)。
|
|
570
590
|
def _cap_text(e, fm, content) -> str:
|
|
571
591
|
"""候选匹配文本:节点标识 + CCG 字段 + 正文(**不含 `fm.tags`**)。"""
|
|
572
592
|
parts = [_as_text(fm.get("title")), e.get("id") or ""]
|
|
@@ -578,6 +598,7 @@ def _cap_text(e, fm, content) -> str:
|
|
|
578
598
|
return " ".join(parts).lower()
|
|
579
599
|
|
|
580
600
|
|
|
601
|
+
# 生效条件:text 包含 CAP_RULES 中某 cap 的至少一个关键词时,该 cap 以匹配关键词与置信度加入返回,按置信度降序、cap 升序排序;无匹配返回空 hits。
|
|
581
602
|
def cap_matches(text: str) -> list:
|
|
582
603
|
hits = []
|
|
583
604
|
for cap, kws in CAP_RULES.items():
|
|
@@ -589,6 +610,7 @@ def cap_matches(text: str) -> list:
|
|
|
589
610
|
return hits
|
|
590
611
|
|
|
591
612
|
|
|
613
|
+
# 生效条件:x 经 _as_cg,遍历 nodes 按 ids/layer 过滤,不可读计 denied,读取失败或加密计 locked,扫描后以 _cap_text 匹配并过滤 confidence >= min_conf 且标签未含 cap:,无命中计 present,有命中则 targeted 并受 limit 限制加入 items,返回 dry_run rep。
|
|
592
614
|
def cap_plan(x, layer=None, limit=None, ids=None, min_conf=0.5) -> dict:
|
|
593
615
|
"""预演:按关键词启发式给出 `cap:<op>` 标签建议(含依据与置信度),不写盘。"""
|
|
594
616
|
cg = _as_cg(x)
|
|
@@ -626,6 +648,7 @@ def cap_plan(x, layer=None, limit=None, ids=None, min_conf=0.5) -> dict:
|
|
|
626
648
|
return rep
|
|
627
649
|
|
|
628
650
|
|
|
651
|
+
# 生效条件:x 经 _as_cg,batch 假值回落 BATCH_DEFAULT;先 cap_plan 得 items,按 entry_ids 过滤;逐个检查节点存在、读取可读、无新增标签分别计 drift/locked/drift,成功写 tags 并记日志,limit 非 None 且 written >= limit 时 break;返回 rep。
|
|
629
652
|
def cap_apply(x, ids=None, entry_ids=None, layer=None, limit=None,
|
|
630
653
|
batch=BATCH_DEFAULT, min_conf=0.5, actor=None) -> dict:
|
|
631
654
|
"""注入 `cap:<op>` 标签:只改 frontmatter.tags,不动正文。"""
|
|
@@ -676,6 +699,7 @@ def cap_apply(x, ids=None, entry_ids=None, layer=None, limit=None,
|
|
|
676
699
|
return rep
|
|
677
700
|
|
|
678
701
|
|
|
702
|
+
# 生效条件:x 经 _as_cg,读取日志中 action=cap 且未回滚的记录,按 batch/entry_ids 过滤,节点存在且原加入标签仍在 tags 中时移除,否则计 conflict/missing,返回 rep。
|
|
679
703
|
def cap_rollback(x, batch=None, entry_ids=None, actor=None) -> dict:
|
|
680
704
|
"""撤销 cap 注入:仅移除**仍在 tags 里**的 `cap:` 标签(防覆盖后续修改)。"""
|
|
681
705
|
cg = _as_cg(x)
|
|
@@ -730,6 +754,7 @@ def cap_rollback(x, batch=None, entry_ids=None, actor=None) -> dict:
|
|
|
730
754
|
EXEMPT_FLAG = "ccg_exempt"
|
|
731
755
|
|
|
732
756
|
|
|
757
|
+
# 生效条件:fm 的 verification_basis 合法且 content 的 ccg_completeness 标记 complete 时返回 (True, []),否则把缺失项放入 miss 返回 ready=False。
|
|
733
758
|
def _exempt_ready(fm: dict, content: str):
|
|
734
759
|
"""摘豁免前置条件 → `(ready, missing)`。
|
|
735
760
|
|
|
@@ -745,6 +770,7 @@ def _exempt_ready(fm: dict, content: str):
|
|
|
745
770
|
return (not miss), miss
|
|
746
771
|
|
|
747
772
|
|
|
773
|
+
# 生效条件:x 经 _as_cg,遍历 nodes 按 ids/prefix/layer 过滤,内部层/不可读/读取失败或加密分别计数跳过,fm 无 EXEMPT_FLAG 计 not_exempt,require_ready 为真且不 ready 时计 unready 并在 want 为 None 时跳过,否则生成 item 受 limit 限制;sample 为真值时按 id 序等距抽取 sample 个。
|
|
748
774
|
def exempt_plan(x, layer=None, limit=None, ids=None, require_ready=True,
|
|
749
775
|
sample=0, prefix=None) -> dict:
|
|
750
776
|
"""预演:列出可摘 `ccg_exempt` 的节点(默认要求证据就绪),不写盘。
|
|
@@ -804,6 +830,7 @@ def exempt_plan(x, layer=None, limit=None, ids=None, require_ready=True,
|
|
|
804
830
|
return rep
|
|
805
831
|
|
|
806
832
|
|
|
833
|
+
# 生效条件:x 经 _as_cg,batch 假值回落 BATCH_DEFAULT;先 exempt_plan 得 items,按 entry_ids 过滤;逐个检查节点存在、可读、EXEMPT_FLAG 仍真、require_ready 为真时 _exempt_ready 再次通过;不通过计 skipped_unready 并记 exempt_skip;通过则置 EXEMPT_FLAG=False 写盘记日志;limit 限制 written;返回 rep。
|
|
807
834
|
def exempt_apply(x, ids=None, entry_ids=None, layer=None, limit=None,
|
|
808
835
|
batch=BATCH_DEFAULT, require_ready=True, actor=None,
|
|
809
836
|
prefix=None) -> dict:
|
|
@@ -864,6 +891,7 @@ def exempt_apply(x, ids=None, entry_ids=None, layer=None, limit=None,
|
|
|
864
891
|
return rep
|
|
865
892
|
|
|
866
893
|
|
|
894
|
+
# 生效条件:当 x 可解析为 cg 时,日志中 action 为 exempt 的记录若其非空 write_id 已存在于既有 action 为 exempt_rollback 的记录 write_id 集合中,则跳过并计入 skipped_done,否则在通过 batch 与 entry_ids 过滤后,节点存在且可读、EXEMPT_FLAG 当前为假时,该记录才被还原并计入 reverted;。
|
|
867
895
|
def exempt_rollback(x, batch=None, entry_ids=None, actor=None) -> dict:
|
|
868
896
|
"""反向还原 `ccg_exempt`:仅当当前仍为「已摘」状态时还原,否则计 conflict。"""
|
|
869
897
|
cg = _as_cg(x)
|
|
@@ -920,6 +948,7 @@ def exempt_rollback(x, batch=None, entry_ids=None, actor=None) -> dict:
|
|
|
920
948
|
# ③ verify_conditions 只读复算:验收指标 legacy_position == 0
|
|
921
949
|
|
|
922
950
|
|
|
951
|
+
# 生效条件:x 经 _as_cg,遍历 nodes 按 prefix/layer 过滤,内部层/不可读/读取失败或加密/derived 层或 SKIP_TAGS 分别计数跳过;扫描后,正文已有生效条件计 declared,derive_fields 可推出计 derivable,否则按 condition_space 缺失槽计 pending 并受 limit 限制收集 items;返回 rep。
|
|
923
952
|
def conditions_pending(x, prefix=None, layer=None, limit=None) -> dict:
|
|
924
953
|
"""只读台账:列出「未声明生效条件、且四槽推不出」的节点及其缺失槽。
|
|
925
954
|
|
|
@@ -978,6 +1007,7 @@ def conditions_pending(x, prefix=None, layer=None, limit=None) -> dict:
|
|
|
978
1007
|
return rep
|
|
979
1008
|
|
|
980
1009
|
|
|
1010
|
+
# 生效条件:cg 的留痕日志中存在 basis 为 LEGACY_CONDITION_BASIS 且未被回滚的 backfill 生效条件写入时,按 node 记录最后一次的 after/original 返回;无匹配返回空。
|
|
981
1011
|
def _legacy_condition_records(cg) -> dict:
|
|
982
1012
|
"""→ {node: {after, original, …}}:我们**自己写下的**单槽冒充行(真源 = 留痕)。
|
|
983
1013
|
|
|
@@ -1005,6 +1035,7 @@ def _legacy_condition_records(cg) -> dict:
|
|
|
1005
1035
|
return out
|
|
1006
1036
|
|
|
1007
1037
|
|
|
1038
|
+
# 生效条件:x 经 _as_cg,从 _legacy_condition_records 取候选,按 prefix 过滤,节点不存在/不可读/读取失败或加密分别计 missing/denied/locked;当前生效条件等于留痕 after 时,四槽合成非空则 rewrite 否则 drop,不等则 conflict;items 受 limit 限制;返回 dry_run rep。
|
|
1008
1039
|
def fix_conditions_plan(x, prefix=None, limit=None) -> dict:
|
|
1009
1040
|
"""预演:清洗存量单槽冒充行。不写盘。
|
|
1010
1041
|
|
|
@@ -1054,6 +1085,7 @@ def fix_conditions_plan(x, prefix=None, limit=None) -> dict:
|
|
|
1054
1085
|
return rep
|
|
1055
1086
|
|
|
1056
1087
|
|
|
1088
|
+
# 生效条件:x 经 _as_cg,batch 假值回落 FIX_BATCH_DEFAULT;先 fix_conditions_plan 得 items,按 ids/entry_ids 过滤;逐个再验当前值仍等于 before 且 comment_before 一致,否则 skipped_drift;rewrite 时 upsert 生效条件行并写 comment,drop 时删行并还原 comment;写盘记 condition_fix,drop 另记 condition_pending;limit 限制 rewritten+dropped;返回 rep。
|
|
1057
1089
|
def fix_conditions_apply(x, ids=None, entry_ids=None, prefix=None, limit=None,
|
|
1058
1090
|
batch=FIX_BATCH_DEFAULT, actor=None) -> dict:
|
|
1059
1091
|
"""执行清洗:`rewrite` 改写为四槽合成声明;`drop` 删行并登记待补。
|
|
@@ -1144,6 +1176,7 @@ def fix_conditions_apply(x, ids=None, entry_ids=None, prefix=None, limit=None,
|
|
|
1144
1176
|
return rep
|
|
1145
1177
|
|
|
1146
1178
|
|
|
1179
|
+
# 生效条件:x 经 _as_cg,读取日志中 action=condition_fix 且未回滚的记录,按 batch/entry_ids 过滤,节点存在且当前生效条件等于 after 时,还原 before(空则删行)并还原 comment_before,否则计 conflict/missing;返回 rep。
|
|
1147
1180
|
def fix_conditions_rollback(x, batch=None, entry_ids=None, actor=None) -> dict:
|
|
1148
1181
|
"""按留痕反向应用:恢复被改写的旧值 / 重建被删除的冒充行。
|
|
1149
1182
|
|
|
@@ -1210,6 +1243,7 @@ def fix_conditions_rollback(x, batch=None, entry_ids=None, actor=None) -> dict:
|
|
|
1210
1243
|
return rep
|
|
1211
1244
|
|
|
1212
1245
|
|
|
1246
|
+
# 生效条件:x 经 _as_cg,遍历 nodes 按 prefix 过滤、内部层跳过,读取失败或加密跳过;对每个节点当前生效条件行,缺失计 absent,否则按 is_legacy_position_condition、等于 _condition_text 合成、等于 comment、其他分别计数,legacy_ids 受 limit 限制;返回 rep。
|
|
1213
1247
|
def verify_conditions(x, prefix=None, limit=None) -> dict:
|
|
1214
1248
|
"""复算核对(只读):生效条件行的来源分布 + 弱等价残留计数。
|
|
1215
1249
|
|
|
@@ -1264,6 +1298,7 @@ ACTIONS = ("backfill", "backfill_rollback", "backfill_history",
|
|
|
1264
1298
|
"exempt", "exempt_rollback", "exempt_history")
|
|
1265
1299
|
|
|
1266
1300
|
|
|
1301
|
+
# 生效条件:按其 action 分派——action=='backfill' 时 kw['apply'] 为真调 apply(x, 去掉 apply 的 kw)、否则调 plan 同参;action=='cap'/'exempt' 同理在 kw['apply'] 为真时调 cap_apply/exempt_apply、否则调 cap_plan/exempt_plan;action=='backfill_rollback'/'cap_rollback'/'exempt_rollback' 分别调 rollback/cap_rollback/exempt_rollback(x, **kw);action=='backfill_history' 调 history(x, **kw),'cap_history'/'exempt_history' 调 history(x, action='cap'/'exempt', **kw);其余 action 值抛 ValueError。
|
|
1267
1302
|
def run(x, action, **kw) -> dict:
|
|
1268
1303
|
"""`maintain` op 的分派入口:action ∈ ACTIONS。"""
|
|
1269
1304
|
if action == "backfill":
|
|
@@ -1290,4 +1325,4 @@ def run(x, action, **kw) -> dict:
|
|
|
1290
1325
|
return exempt_rollback(x, **kw)
|
|
1291
1326
|
if action == "exempt_history":
|
|
1292
1327
|
return history(x, action="exempt", **kw)
|
|
1293
|
-
raise ValueError(f"未知 backfill action:{action}(允许:{ACTIONS})")
|
|
1328
|
+
raise ValueError(f"未知 backfill action:{action}(允许:{ACTIONS})")
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""big_domain 域标签回填(S1 大域收敛的前置元数据;幂等、支持 --dry-run)。
|
|
3
|
+
|
|
4
|
+
用法:
|
|
5
|
+
python -X utf8 -m md_cg.backfill_bigdomain --root <库根> [--dry-run] [--limit N]
|
|
6
|
+
|
|
7
|
+
为何需要单独的回填入口:域标签是**写入侧**新增的元数据,存量节点没有;
|
|
8
|
+
S1 要按域收敛,就必须先把存量补齐(契约 §8.1)。
|
|
9
|
+
"""
|
|
10
|
+
import argparse
|
|
11
|
+
import json
|
|
12
|
+
import sys
|
|
13
|
+
|
|
14
|
+
from .mdcg import MdCG
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# 生效条件:无条件解析参数(root 必填,dry_run/limit 可选)、以 MdCG(root) 打开库、调用 backfill_big_domain 并把统计 dict 以 JSON 打印,返回 0。
|
|
18
|
+
def main(argv=None):
|
|
19
|
+
ap = argparse.ArgumentParser()
|
|
20
|
+
ap.add_argument("--root", required=True, help="库根目录")
|
|
21
|
+
ap.add_argument("--dry-run", action="store_true", dest="dry_run",
|
|
22
|
+
help="只统计不改盘")
|
|
23
|
+
ap.add_argument("--limit", type=int, default=None, help="最多补写多少个节点")
|
|
24
|
+
a = ap.parse_args(argv)
|
|
25
|
+
cg = MdCG(a.root)
|
|
26
|
+
st = cg.backfill_big_domain(dry_run=a.dry_run, limit=a.limit)
|
|
27
|
+
print(json.dumps(st, ensure_ascii=False))
|
|
28
|
+
return 0
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if __name__ == "__main__":
|
|
32
|
+
if hasattr(sys.stdout, "reconfigure"):
|
|
33
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
34
|
+
sys.exit(main())
|