@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/conformance.py
CHANGED
|
@@ -42,8 +42,10 @@ DEFAULT_ROOT = os.path.join(
|
|
|
42
42
|
AUDIT_TAIL = 20000
|
|
43
43
|
|
|
44
44
|
|
|
45
|
+
# 生效条件:无入参,datapath.mdcg_root() 返回真值时返回该值,导入或调用抛异常、或返回假值(如空串)时返回模块常量 DEFAULT_ROOT;
|
|
45
46
|
def _default_root() -> str:
|
|
46
|
-
"""根解析沿用本仓约定:env `MDCG_ROOT` > `
|
|
47
|
+
"""根解析沿用本仓约定:env `MDCG_ROOT` > `paths.json`(用户级,旧包内兼容读)
|
|
48
|
+
> 用户级状态根 `data/mdcg`。
|
|
47
49
|
|
|
48
50
|
走 `datapath.mdcg_root()`(兜底纪律:与其它工具同源解析,不另立一套)。
|
|
49
51
|
"""
|
|
@@ -115,6 +117,7 @@ NEW_TYPE_TOUCHPOINTS = {
|
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
|
|
120
|
+
# 生效条件:root 下 INDEX_FILE 可读且 JSON 顶层为 dict 并含 nodes 字典时返回该 nodes;不可读抛 OSError、JSON 非法抛 JSONDecodeError、nodes 非 dict 抛 ValueError;
|
|
118
121
|
def load_index(root: str) -> dict:
|
|
119
122
|
"""读索引快照(唯一必需数据源);损坏即抛——断言集不建立在猜测上。"""
|
|
120
123
|
with open(os.path.join(root, INDEX_FILE), encoding="utf-8") as f:
|
|
@@ -125,6 +128,7 @@ def load_index(root: str) -> dict:
|
|
|
125
128
|
return nodes
|
|
126
129
|
|
|
127
130
|
|
|
131
|
+
# 生效条件:path 不存在(os.path.exists 为假)时返回 [];存在时逐行解析,空行与 JSONDecodeError 行被跳过,返回可解析记录的列表(可能为 []);
|
|
128
132
|
def _read_jsonl(path: str) -> list:
|
|
129
133
|
if not os.path.exists(path):
|
|
130
134
|
return []
|
|
@@ -141,10 +145,12 @@ def _read_jsonl(path: str) -> list:
|
|
|
141
145
|
return out
|
|
142
146
|
|
|
143
147
|
|
|
148
|
+
# 生效条件:rec 的 tags 缺失或为假值时按空列表处理,仅对含 ":" 的 tag 取首个冒号前的前缀构成集合并返回;无此类 tag 时返回空集合;
|
|
144
149
|
def _tag_prefixes(rec: dict) -> set:
|
|
145
150
|
return {str(t).split(":", 1)[0] for t in (rec.get("tags") or []) if ":" in str(t)}
|
|
146
151
|
|
|
147
152
|
|
|
153
|
+
# 生效条件:r 的 verification_basis 为 list/tuple 时返回其真值元素的 str 列表;否则该值真值时返回 [str(b)],缺失或为假值(None/空串/空容器)时返回 [];
|
|
148
154
|
def _basis_of(r: dict):
|
|
149
155
|
b = r.get("verification_basis")
|
|
150
156
|
if isinstance(b, (list, tuple)):
|
|
@@ -152,11 +158,13 @@ def _basis_of(r: dict):
|
|
|
152
158
|
return [str(b)] if b else []
|
|
153
159
|
|
|
154
160
|
|
|
161
|
+
# 生效条件:无入参,返回 layer(取自导入的模块常量 LAYERS 的排序值)+ edge_type/derived_relation/verification_basis/lifecycle_state 五键声明值映射,后四键对应模块导入或属性取值失败、属性值为假值(空容器/None)时该键 declared=None;
|
|
155
162
|
def enum_spaces() -> dict:
|
|
156
163
|
"""各类型空间的声明值(模块真源取不到 → declared=None,报告标 BLINDSPOT)。"""
|
|
157
164
|
from .mdcg import LAYERS
|
|
158
165
|
spaces = {"layer": {"declared": sorted(LAYERS), "source": "mdcg.LAYERS"}}
|
|
159
166
|
|
|
167
|
+
# 生效条件:以 md_cg.<mod> 导入并 getattr(attr)(导入或取值抛异常则 val=None),把 {"declared": sorted(val) if val else None, "source": "<mod>.<attr>"} 写入片段外闭包变量 spaces 的 key 键(val 为假值时 declared=None),无返回值;
|
|
160
168
|
def _grab(mod: str, attr: str, key: str):
|
|
161
169
|
try:
|
|
162
170
|
m = __import__(f"md_cg.{mod}", fromlist=[attr])
|
|
@@ -175,6 +183,7 @@ def enum_spaces() -> dict:
|
|
|
175
183
|
|
|
176
184
|
# ---------------------------- 指标 ----------------------------
|
|
177
185
|
|
|
186
|
+
# 生效条件:对 nodes 各记录按 str(content_hash) 计数,content_hash 缺失被折成 "None",返回出现次数 >1 且哈希不为 "None"/"" 的组数、涉及节点数与前 5 大组大小;
|
|
178
187
|
def _dup_metrics(nodes: dict) -> dict:
|
|
179
188
|
ch = Counter(str(r.get("content_hash")) for r in nodes.values())
|
|
180
189
|
groups = {h: c for h, c in ch.items() if c > 1 and h not in ("None", "")}
|
|
@@ -182,6 +191,7 @@ def _dup_metrics(nodes: dict) -> dict:
|
|
|
182
191
|
"largest": sorted(groups.values(), reverse=True)[:5]}
|
|
183
192
|
|
|
184
193
|
|
|
194
|
+
# 生效条件:对 nodes 中每个节点的 "edges" 真值且为 list/tuple 的边列表,仅遍历其中 dict 边;依据 CANONICAL_EDGE_KEYS 与 "type" 统计键组合、关系类型、总边数、非规范键样本(最多 5)和悬空边,返回汇总字典。
|
|
185
195
|
def _edge_metrics(nodes: dict) -> dict:
|
|
186
196
|
types, key_mix = Counter(), Counter()
|
|
187
197
|
total = dangling = with_edges = non_canonical = 0
|
|
@@ -210,6 +220,7 @@ def _edge_metrics(nodes: dict) -> dict:
|
|
|
210
220
|
"non_canonical": non_canonical, "dangling": dangling, "samples": samples}
|
|
211
221
|
|
|
212
222
|
|
|
223
|
+
# 生效条件:遍历 nodes 的值作为记录,path 经 str(r.get("path") or "") 为空即 missing++ 并 continue,不以记录含 layer/path 为前置;仅对非空 path 执行 layer 与 head 检查(layer 非空且 head != layer 且 head in LAYER_DIRS 时 layer_mismatch++),且 check_exists 为 True 时才对非空 path 以 os.path.join(root, rel) 判断不存在并计入 missing,最终返回 missing/layer_mismatch/samples 统计;。
|
|
213
224
|
def _path_metrics(root: str, nodes: dict, check_exists: bool) -> dict:
|
|
214
225
|
missing = mismatch = 0
|
|
215
226
|
samples = []
|
|
@@ -233,6 +244,7 @@ def _path_metrics(root: str, nodes: dict, check_exists: bool) -> dict:
|
|
|
233
244
|
return {"missing": missing, "layer_mismatch": mismatch, "samples": samples}
|
|
234
245
|
|
|
235
246
|
|
|
247
|
+
# 生效条件:root 下 DECISION_LOG/INBOX_LOG 不存在时按空列表计,返回 decisions(decision 或 status 回落 "?" 的前 10 项)、decisions_total、inbox_pending=max(0, 收件数−决策数)、以及 _audit.jsonl 末尾 AUDIT_TAIL 行内 op 计数的前 6 项与尾窗元信息;
|
|
236
248
|
def _gate_metrics(root: str) -> dict:
|
|
237
249
|
dec = _read_jsonl(os.path.join(root, DECISION_LOG))
|
|
238
250
|
inbox = _read_jsonl(os.path.join(root, INBOX_LOG))
|
|
@@ -259,6 +271,7 @@ def _gate_metrics(root: str) -> dict:
|
|
|
259
271
|
"audit_tail_window": AUDIT_TAIL}
|
|
260
272
|
|
|
261
273
|
|
|
274
|
+
# 生效条件:对 root 与 nodes,若 root/ACCESS_LOG 路径不存在则返回 {"distinct": None, "ratio": None, "lines": None};否则逐行解析 JSON,当 "ids" 为 list 或 tuple 时把其中真值元素 str 后加入 seen,且当 "id"/"node_id"/"nid" 任一真值时把其 str 加入 seen,返回 distinct 为 seen 与 nodes 键交集数量、ratio 为 distinct/max(len(nodes),1)、lines 为非空行数。
|
|
262
275
|
def _reach_metrics(root: str, nodes: dict) -> dict:
|
|
263
276
|
p = os.path.join(root, ACCESS_LOG)
|
|
264
277
|
if not os.path.exists(p):
|
|
@@ -285,6 +298,7 @@ def _reach_metrics(root: str, nodes: dict) -> dict:
|
|
|
285
298
|
return {"distinct": hit, "ratio": hit / max(len(nodes), 1), "lines": lines}
|
|
286
299
|
|
|
287
300
|
|
|
301
|
+
# 生效条件:对 nodes,筛出 layer 字符串为 "knowledge" 的 kn;mixed 为 kn 中标签前缀含 doc 或 code 的数量;返回全库 nodes 数与 knowledge 层数、mixed、mixed_ratio=mixed/max(len(kn),1),以及全库口径 role_ratio/basis_ratio/evidence_ratio/state_ratio 和 knowledge 层口径 role_ratio_kn/basis_ratio_kn/evidence_ratio_kn。
|
|
288
302
|
def _coverage_metrics(nodes: dict) -> dict:
|
|
289
303
|
"""混层口径 + 字段覆盖率(9-15 审计基线口径,逐项可复现)。
|
|
290
304
|
|
|
@@ -311,6 +325,7 @@ def _coverage_metrics(nodes: dict) -> dict:
|
|
|
311
325
|
if _as_int(r.get("evidence_count")) > 0) / nk}
|
|
312
326
|
|
|
313
327
|
|
|
328
|
+
# 生效条件:int(v) 转换成功时返回该整数;抛 TypeError/ValueError(如 None、非数字串)时返回 0;
|
|
314
329
|
def _as_int(v) -> int:
|
|
315
330
|
try:
|
|
316
331
|
return int(v)
|
|
@@ -320,6 +335,7 @@ def _as_int(v) -> int:
|
|
|
320
335
|
|
|
321
336
|
# ---------------------------- G3 · unanalyzed 派生集合 ----------------------------
|
|
322
337
|
|
|
338
|
+
# 生效条件:仅当记录 _as_int(evidence_count)==0 且 verification_basis 为空且 lifecycle_state 为假值时计入 ids,返回 count、ratio=count/max(len(nodes),1) 与前 5 个 id 样本;
|
|
323
339
|
def unanalyzed(nodes: dict) -> dict:
|
|
324
340
|
"""G3:unanalyzed **派生**判据(不新增字段、零写入)。
|
|
325
341
|
|
|
@@ -342,6 +358,7 @@ def unanalyzed(nodes: dict) -> dict:
|
|
|
342
358
|
|
|
343
359
|
# ---------------------------- G1 · 类型空间正交性审计 ----------------------------
|
|
344
360
|
|
|
361
|
+
# 生效条件:调用 _usage(nodes, edges) 时 edges 形参未被源码引用,对 nodes.values() 中每个节点 r,仅当 r.get("layer")、r.get("role")、r.get("derived_relation")、r.get("lifecycle_state") 为真值时分别以 str 值计入对应 Counter,_basis_of(r) 与 _tag_prefixes(r) 展开的元素分别计入 verification_basis 与 tag_prefix,再遍历各 r 的 r.get("edges") or [] 中 isinstance(e, dict) 的项按 edge_rel(e) 计数,最终 edge_type 仅保留键为真值的计数,返回 used 字典;
|
|
345
362
|
def _usage(nodes: dict, edges: dict) -> dict:
|
|
346
363
|
"""各类型空间的**实测**取值(与 enum_spaces 的声明值对照)。"""
|
|
347
364
|
from .chain import edge_rel
|
|
@@ -364,6 +381,7 @@ def _usage(nodes: dict, edges: dict) -> dict:
|
|
|
364
381
|
return used
|
|
365
382
|
|
|
366
383
|
|
|
384
|
+
# 生效条件:以 enum_spaces 的声明集与 _usage 的实测集逐空间对照(closed 仅在 declared 非 None 且无未声明已用时为 True),role 与 tag_prefix 两空间的 declared/closed 恒为 None,另附 _cross_space_overlap(字面量出现在 ≥2 空间或 layer∩tag_prefix)及 KNOWN_DIRECTION_CONFLICTS/VERIFIED_CONSISTENT/DOC_CODE_DRIFT/NEW_TYPE_TOUCHPOINTS 四个常量;
|
|
367
385
|
def _g1_audit(nodes: dict, edges: dict) -> dict:
|
|
368
386
|
"""G1:声明值 / 实测值 / 未声明已用 / 声明未用 / 跨空间重叠 / 方向口径分歧。"""
|
|
369
387
|
spaces = enum_spaces()
|
|
@@ -401,10 +419,12 @@ def _g1_audit(nodes: dict, edges: dict) -> dict:
|
|
|
401
419
|
|
|
402
420
|
# ---------------------------- 断言集 ----------------------------
|
|
403
421
|
|
|
422
|
+
# 生效条件:四参齐备时返回 {"id": cid, "level": level, "ok": bool(ok), "detail": detail},ok 经 bool() 归一为布尔;
|
|
404
423
|
def _ck(cid: str, level: str, ok: bool, detail: str) -> dict:
|
|
405
424
|
return {"id": cid, "level": level, "ok": bool(ok), "detail": detail}
|
|
406
425
|
|
|
407
426
|
|
|
427
|
+
# 生效条件:调用 check(root, check_paths, baseline, strict) 时,root 原样传入 load_index 得 nodes,check_paths 原样传入 _path_metrics 并在 index.path.present 检查消息中当其为假时追加“(--no-path-check 未查盘)”,baseline 为真时追加 _regression 基线不劣化检查、为假(None 或空 dict)时跳过,n=len(nodes) 小于 THRESHOLDS["min_nodes"] 时 small 为真且使 _ratio 各项及 reach.ratio、stratum.mixed_ratio 在 val 为 None 或 small 为真时记 BLINDSPOT、否则记 WARN,最终 verdict 为 FAIL(存在 level="FAIL" 且 ok 为假)、否则 WARN(存在 level="WARN" 且 ok 为假,或 strict 为真且存在 level="BLINDSPOT")、否则 PASS,返回含 REPORT_VERSION、t、elapsed_s、root 绝对路径、verdict、nodes、checks、counts、coverage、dup、edges、paths、gate、reach、unanalyzed、g1、protocol(=protocol.audit() 静态对账,恒追加四条 FAIL 级断言:op.declared 无未登记分支 / verb.implemented live 动词均有实现分支 / verb.reserved_clean 预留动词未被静默实现 / shape.declared 形状声明完备)、thresholds 的 dict;
|
|
408
428
|
def check(root: str, *, check_paths: bool = True,
|
|
409
429
|
baseline: dict = None, strict: bool = False) -> dict:
|
|
410
430
|
"""跑一遍全部断言,返回报告 dict(零写入:不修任何数据、不落任何文件)。"""
|
|
@@ -452,6 +472,7 @@ def check(root: str, *, check_paths: bool = True,
|
|
|
452
472
|
f" / 最大组 {dup['largest'][:3]}(最大组上限 {DUP_GROUP_MAX})"))
|
|
453
473
|
|
|
454
474
|
# ---- 健康指标(只告警)----
|
|
475
|
+
# 生效条件:val 为 None 或片段外闭包布尔 small 为真(small、n、T 均未在本片段定义)时追加 level="BLINDSPOT" 项;否则追加 level="WARN"、ok=(val>=low) 的项;两分支均无返回值;
|
|
455
476
|
def _ratio(cid, val, low, name):
|
|
456
477
|
if small or val is None:
|
|
457
478
|
checks.append(_ck(cid, "BLINDSPOT", True,
|
|
@@ -478,6 +499,33 @@ def check(root: str, *, check_paths: bool = True,
|
|
|
478
499
|
f"闸门裁决样本 {gate['decisions_total']} 条 {gate['decisions']}"
|
|
479
500
|
f"(下限 {T['gate_sample_min']})"))
|
|
480
501
|
|
|
502
|
+
# ---- 记忆动词协议 v1 静态对账(声明 ↔ MCP 面实现,纯源码事实、不连库)----
|
|
503
|
+
# 与 G1 的分工:G1 对账**数据值域**,这里对账**动词面**——两者都是
|
|
504
|
+
# 「声明了没做 / 做了没说」的前置红灯,属结构性不变量(FAIL 级,fail-closed)。
|
|
505
|
+
from . import protocol as _proto
|
|
506
|
+
pa = _proto.audit()
|
|
507
|
+
checks.append(_ck("protocol.op.extension_surface", "WARN", True,
|
|
508
|
+
f"协议 v{pa['protocol_version']} 冻结面={pa['declared']}"
|
|
509
|
+
f"(live {len(pa['live'])} / reserved {len(pa['reserved'])});"
|
|
510
|
+
f"MCP 面另有 {len(pa['extension_ops'])} 个扩展 op 不属协议面"
|
|
511
|
+
f"(文档一致性由 cogmap 门禁承担)"))
|
|
512
|
+
checks.append(_ck("protocol.verb.implemented", "FAIL",
|
|
513
|
+
not pa["missing_impl"],
|
|
514
|
+
f"声明为 live 的动词 {pa['live']} 均有实现分支"
|
|
515
|
+
if not pa["missing_impl"] else
|
|
516
|
+
f"声明为 live 却无实现分支:{pa['missing_impl']}"))
|
|
517
|
+
checks.append(_ck("protocol.verb.reserved_clean", "FAIL",
|
|
518
|
+
not pa["reserved_leaked"],
|
|
519
|
+
f"reserved 动词 {pa['reserved']} 未出现实现分支"
|
|
520
|
+
if not pa["reserved_leaked"] else
|
|
521
|
+
f"reserved 动词被静默实现(须先改 status=live):"
|
|
522
|
+
f"{pa['reserved_leaked']}"))
|
|
523
|
+
checks.append(_ck("protocol.shape.declared", "FAIL",
|
|
524
|
+
not pa["shape_errors"],
|
|
525
|
+
f"{len(pa['declared'])} 个动词形状声明完备"
|
|
526
|
+
if not pa["shape_errors"] else
|
|
527
|
+
f"形状声明不完整:{pa['shape_errors']}"))
|
|
528
|
+
|
|
481
529
|
# ---- 基线不劣化(有 baseline 时才可判)----
|
|
482
530
|
if baseline:
|
|
483
531
|
checks += _regression({"mixed_ratio": cov["mixed_ratio"],
|
|
@@ -497,9 +545,10 @@ def check(root: str, *, check_paths: bool = True,
|
|
|
497
545
|
"total": len(checks)},
|
|
498
546
|
"coverage": cov, "dup": dup, "edges": edges, "paths": paths,
|
|
499
547
|
"gate": gate, "reach": reach, "unanalyzed": un, "g1": g1,
|
|
500
|
-
"thresholds": T}
|
|
548
|
+
"protocol": pa, "thresholds": T}
|
|
501
549
|
|
|
502
550
|
|
|
551
|
+
# 生效条件:对 cur 各键,baseline(或其 metrics)缺失、该键在基线为 None 或 cur 值为 None 时跳过;否则以 val > b+1e-9 判劣化,产出 level 恒为 "FAIL"、ok=not worse 的检查项;
|
|
503
552
|
def _regression(cur: dict, baseline: dict) -> list:
|
|
504
553
|
"""与基线比对:单调量只准不变或改善(重复度/悬空/非规范键/混层/unanalyzed)。
|
|
505
554
|
|
|
@@ -519,6 +568,7 @@ def _regression(cur: dict, baseline: dict) -> list:
|
|
|
519
568
|
return out
|
|
520
569
|
|
|
521
570
|
|
|
571
|
+
# 生效条件:rep 含 coverage/edges/dup/unanalyzed/gate/reach 子字典与 nodes 键时(全部按下标取值,缺键即抛 KeyError)返回扁平指标映射;
|
|
522
572
|
def metrics_of(rep: dict) -> dict:
|
|
523
573
|
"""抽成可比对的扁平指标(--baseline 的写入面)。"""
|
|
524
574
|
return {"mixed_ratio": rep["coverage"]["mixed_ratio"],
|
|
@@ -538,6 +588,7 @@ def metrics_of(rep: dict) -> dict:
|
|
|
538
588
|
|
|
539
589
|
# ---------------------------- 报告 ----------------------------
|
|
540
590
|
|
|
591
|
+
# 生效条件:rep 各键齐备(按下标取值,任一键缺失抛 KeyError)时拼接为多行文本,reach.ratio 为 None 时渲染 "N/A",g1 中以 "_" 开头的键在遍历中被跳过;
|
|
541
592
|
def render(rep: dict) -> str:
|
|
542
593
|
L = []
|
|
543
594
|
a = L.append
|
|
@@ -573,6 +624,17 @@ def render(rep: dict) -> str:
|
|
|
573
624
|
f"/{rep['gate']['audit_tail_window']} 行)={rep['gate']['audit_ops']}")
|
|
574
625
|
a(f" G3 unanalyzed 派生={rep['unanalyzed']['count']}"
|
|
575
626
|
f" ({rep['unanalyzed']['ratio'] * 100:.1f}%)")
|
|
627
|
+
pr = rep.get("protocol") or {}
|
|
628
|
+
if pr:
|
|
629
|
+
a("\n-- 记忆动词协议 v1 静态对账 --")
|
|
630
|
+
a(f" {pr['doc']} frozen={pr['frozen']} ok={pr['ok']}")
|
|
631
|
+
a(f" 声明={pr['declared']}")
|
|
632
|
+
a(f" live={pr['live']} reserved={pr['reserved']}(未实现即如实登记,不冒充)")
|
|
633
|
+
a(f" MCP 面 op 分支={len(pr['actual'])} 个,其中扩展能力面"
|
|
634
|
+
f"(不属协议 v1){len(pr['extension_ops'])} 个")
|
|
635
|
+
if pr["errors"]:
|
|
636
|
+
for e in pr["errors"]:
|
|
637
|
+
a(f" !! {e}")
|
|
576
638
|
a("\n-- G1 类型空间正交性 --")
|
|
577
639
|
for name, spec in rep["g1"].items():
|
|
578
640
|
if name.startswith("_"):
|
|
@@ -591,6 +653,7 @@ def render(rep: dict) -> str:
|
|
|
591
653
|
return "\n".join(L)
|
|
592
654
|
|
|
593
655
|
|
|
656
|
+
# 生效条件:传入对象可写属性时执行赋值 sustain_module.conformance_summary = report_summary,无返回值(None);
|
|
594
657
|
def register_sustain(sustain_module) -> None: # pragma: no cover
|
|
595
658
|
"""挂点说明(供 sustain 侧最小侵入调用)。
|
|
596
659
|
|
|
@@ -601,6 +664,7 @@ def register_sustain(sustain_module) -> None: # pragma: no cover
|
|
|
601
664
|
sustain_module.conformance_summary = report_summary
|
|
602
665
|
|
|
603
666
|
|
|
667
|
+
# 生效条件:root 依次取 cg_or_root.root 属性、cg_or_root 本身、_default_root()(前者为假值即回落,故 0/空串会继续回落);check 抛异常时返回 ok=False、verdict="BLINDSPOT"、error,否则返回 ok=(verdict!="FAIL") 与 fail/warn/blindspot/failed_ids/t;
|
|
604
668
|
def report_summary(cg_or_root) -> dict:
|
|
605
669
|
"""给常驻循环用的**轻量**结论(不渲染全文、不写盘):verdict + 计数。"""
|
|
606
670
|
root = getattr(cg_or_root, "root", None) or cg_or_root or _default_root()
|
|
@@ -616,11 +680,12 @@ def report_summary(cg_or_root) -> dict:
|
|
|
616
680
|
"t": rep["t"]}
|
|
617
681
|
|
|
618
682
|
|
|
683
|
+
# 生效条件:argv 为 None 时 argparse 从 sys.argv 取值,--root 缺失或为假值回落 _default_root();check 抛 OSError/ValueError(如索引不可读)时打印 BLINDSPOT 并返回 2,否则按 --write-baseline/--json 写盘后返回 0(verdict≠"FAIL")或 1("FAIL");
|
|
619
684
|
def main(argv=None) -> int:
|
|
620
685
|
p = argparse.ArgumentParser(prog="python -m md_cg.conformance",
|
|
621
686
|
description="数据健康不变量断言集(只读,零写入)")
|
|
622
687
|
p.add_argument("--root", default=None,
|
|
623
|
-
help="认知图根(默认 MDCG_ROOT >
|
|
688
|
+
help="认知图根(默认 MDCG_ROOT > paths.json > 用户级状态根 data/mdcg)")
|
|
624
689
|
p.add_argument("--json", dest="json_out", default=None)
|
|
625
690
|
p.add_argument("--baseline", default=None, help="基线报告 json(比对不劣化)")
|
|
626
691
|
p.add_argument("--write-baseline", default=None, help="把本次指标写成新基线")
|
|
@@ -659,4 +724,4 @@ def main(argv=None) -> int:
|
|
|
659
724
|
if __name__ == "__main__":
|
|
660
725
|
if hasattr(sys.stdout, "reconfigure"):
|
|
661
726
|
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
662
|
-
sys.exit(main())
|
|
727
|
+
sys.exit(main())
|
package/md_cg/consistency.py
CHANGED
|
@@ -81,9 +81,11 @@ DISCIPLINE_TAGS = ("discipline", "纪律", "work_discipline", "rule", "规则",
|
|
|
81
81
|
VERDICTS = ("ACCEPT", "REJECT", "DEFER", "BLINDSPOT")
|
|
82
82
|
|
|
83
83
|
|
|
84
|
+
# 生效条件:以 verdict 与 reason 构造异常(消息 `[{verdict}] {reason}`),conflicts 传假值(None/空容器等,源码 `conflicts or []`)时 self.conflicts 为 [],传真值时原样保留;
|
|
84
85
|
class ConsistencyError(Exception):
|
|
85
86
|
"""硬冲突:写入被拒(自否定 / 违反纪律)。"""
|
|
86
87
|
|
|
88
|
+
# 生效条件:verdict 与 reason 必传并赋给同名属性、拼成异常消息 `[{verdict}] {reason}`;conflicts 为假值(None/空容器等,源码 `conflicts or []`)时 self.conflicts 回落到 [],为真值时原样保留;
|
|
87
89
|
def __init__(self, verdict, reason, conflicts=None):
|
|
88
90
|
self.verdict = verdict
|
|
89
91
|
self.reason = reason
|
|
@@ -95,6 +97,7 @@ class ConsistencyError(Exception):
|
|
|
95
97
|
# 原语:延迟导入 mdcos(避免 mdcg ← mdcos ← consistency 的循环导入)
|
|
96
98
|
# --------------------------------------------------------------------------
|
|
97
99
|
|
|
100
|
+
# 生效条件:无 required 形参,任一调用返回 ( _ccg_field, _declared_conditions, _neg_hit, _weighted_coverage ) 四元组;
|
|
98
101
|
def _prims():
|
|
99
102
|
"""取 md_cg 已有的条件匹配原语(条件论「反题」的既有实现)。"""
|
|
100
103
|
from .mdcos import (_ccg_field, _declared_conditions, _neg_hit,
|
|
@@ -102,6 +105,7 @@ def _prims():
|
|
|
102
105
|
return _ccg_field, _declared_conditions, _neg_hit, _weighted_coverage
|
|
103
106
|
|
|
104
107
|
|
|
108
|
+
# 生效条件:xs 为可迭代对象时,逐项 str(x).strip() 后仅当结果非空且未出现过才加入 out 并返回 out;xs 为 None/False/0 时在 for 处迭代失败(TypeError);
|
|
105
109
|
def _dedup(xs):
|
|
106
110
|
out = []
|
|
107
111
|
for x in xs:
|
|
@@ -111,6 +115,7 @@ def _dedup(xs):
|
|
|
111
115
|
return out
|
|
112
116
|
|
|
113
117
|
|
|
118
|
+
# 生效条件:fm 给出时,遍历 fm.get("edges")(缺键或假值按空列表)中元素,dict 元素按 to→target→node→id 取首个真值、非 dict 元素直接作候选,候选真值时 str(t) 加入 out 并返回;
|
|
114
119
|
def _edge_targets(fm):
|
|
115
120
|
"""节点声明的出边目标(兼容 dict / str 两种形态)。"""
|
|
116
121
|
out = []
|
|
@@ -124,6 +129,7 @@ def _edge_targets(fm):
|
|
|
124
129
|
return out
|
|
125
130
|
|
|
126
131
|
|
|
132
|
+
# 生效条件:fm 与 node_id 给出时,若 fm.get("tags")(缺键/假值按空)小写后与 DISCIPLINE_TAGS 有交集,或 str(node_id) 以 "discipline_" 或 "work_discipline" 开头,返回 True;否则返回 False;
|
|
127
133
|
def _is_discipline(fm, node_id):
|
|
128
134
|
tags = {str(t).lower() for t in (fm.get("tags") or [])}
|
|
129
135
|
if tags & set(DISCIPLINE_TAGS):
|
|
@@ -139,6 +145,7 @@ def _is_discipline(fm, node_id):
|
|
|
139
145
|
SEPARATION_REL = "distinct_from"
|
|
140
146
|
|
|
141
147
|
|
|
148
|
+
# 生效条件:fm 给出时,仅处理 fm.get("edges")(缺键/假值按空)中的 dict 元素,relation_type 或 relation(缺省空串)小写等于 SEPARATION_REL 时,按 target→to→id 取首个真值且未重复则加入 out;
|
|
142
149
|
def separation_targets(fm):
|
|
143
150
|
"""节点已声明的分离对象(`distinct_from` 出边),用于幂等与去重。"""
|
|
144
151
|
out = []
|
|
@@ -154,6 +161,7 @@ def separation_targets(fm):
|
|
|
154
161
|
return out
|
|
155
162
|
|
|
156
163
|
|
|
164
|
+
# 生效条件:fm 与 content 给出时,以 content(假值按空串)、fm.get("condition_space")、fm.get("non_applicable_conditions") 解析,返回去重后的 (set(pos), set(neg));
|
|
157
165
|
def condition_terms(fm, content):
|
|
158
166
|
"""节点声明的(正条件, 负条件)词面集合——分离判定与重构取线索共用。"""
|
|
159
167
|
pos, neg = _new_terms(content or "", fm.get("condition_space"),
|
|
@@ -161,6 +169,7 @@ def condition_terms(fm, content):
|
|
|
161
169
|
return set(pos), set(neg)
|
|
162
170
|
|
|
163
171
|
|
|
172
|
+
# 生效条件:pos_a、neg_a、pos_b、neg_b 给出的条件词面小写化后,两侧并集均空时返回 overlap 0.0、distinct False;否则计算交集/并集比并返回 distinct 为 overlap <= CLASH_LOW;
|
|
164
173
|
def condition_distinct(pos_a, neg_a, pos_b, neg_b):
|
|
165
174
|
"""两组条件是否「实质不同」:任一侧条件词面几乎不重合即为不同情境。
|
|
166
175
|
|
|
@@ -177,6 +186,7 @@ def condition_distinct(pos_a, neg_a, pos_b, neg_b):
|
|
|
177
186
|
return {"overlap": round(overlap, 4), "distinct": overlap <= CLASH_LOW}
|
|
178
187
|
|
|
179
188
|
|
|
189
|
+
# 生效条件:content、condition_space、non_applicable_conditions 给出时,content 的 `生效条件` 字段与 condition_space 中键不以 `__` 开头且不为 `time_window` 的值并入 pos(list/tuple/set 展平,其他非 None/"" 值 str 化),non_applicable_conditions 各项及 content 的 `不适用条件` 字段值并入 neg,最后 _dedup 返回;
|
|
180
190
|
def _new_terms(content, condition_space, non_applicable_conditions):
|
|
181
191
|
"""新节点声明的(正条件, 负条件)——与既有节点同口径解析。"""
|
|
182
192
|
_ccg_field, _declared, _neg_hit, _cov = _prims()
|
|
@@ -198,6 +208,7 @@ def _new_terms(content, condition_space, non_applicable_conditions):
|
|
|
198
208
|
return _dedup(pos), _dedup(neg)
|
|
199
209
|
|
|
200
210
|
|
|
211
|
+
# 生效条件:content 与 neg_texts 给出时,neg_texts 中任一短语去掉「不得/禁止/严禁/不能/不可/不要/勿」前缀且长度 >=2 后作为子串出现在 content(假值按空串)中则返回 True,否则 False;
|
|
201
212
|
def _ban_hit(content, neg_texts):
|
|
202
213
|
"""纪律禁令命中:去掉「不得/禁止/…」前缀后,短语是否**整体出现**在正文中。
|
|
203
214
|
|
|
@@ -215,6 +226,7 @@ def _ban_hit(content, neg_texts):
|
|
|
215
226
|
return False
|
|
216
227
|
|
|
217
228
|
|
|
229
|
+
# 生效条件:content 为真时按行过滤,跳过 strip 后以 "#" 开头且含全角或半角冒号的行,其余原行以换行连接返回;content 假值按空串返回 "";
|
|
218
230
|
def _body_text(content):
|
|
219
231
|
"""去掉 CCG 声明行(`# 字段:值`)后的正文。
|
|
220
232
|
|
|
@@ -231,6 +243,7 @@ def _body_text(content):
|
|
|
231
243
|
return "\n".join(out)
|
|
232
244
|
|
|
233
245
|
|
|
246
|
+
# 生效条件:content 给出时(假值按空串)解析 CCG 的 `# 功能名` 与 `# 子功能` 字段并返回两者;
|
|
234
247
|
def _slot_text(content):
|
|
235
248
|
"""结论槽:CCG 声明的 `# 功能名` / `# 子功能`(结构字段,非正文词面)。
|
|
236
249
|
|
|
@@ -250,6 +263,7 @@ def _slot_text(content):
|
|
|
250
263
|
# L0 情绪通道(信息差二阶变化)
|
|
251
264
|
# --------------------------------------------------------------------------
|
|
252
265
|
|
|
266
|
+
# 生效条件:conflict_strength 被夹取到 [0,1](假值按 0.0),prev_strength 为 None 时 d2=0.0,否则 d2=c-夹取后的 prev_strength;按 c>=EMO_AVOID 或 d2>0.2 返回 avoiding,或 c<=EMO_APPROACH 且 d2<=0 返回 approaching,否则 stable;
|
|
253
267
|
def emotional_bias(conflict_strength, prev_strength=None):
|
|
254
268
|
"""L0:把冲突强度映射为情绪倾向(approaching / stable / avoiding)。
|
|
255
269
|
|
|
@@ -279,6 +293,7 @@ def emotional_bias(conflict_strength, prev_strength=None):
|
|
|
279
293
|
"note": "情绪通道独立,不参与信任/资格计算(智能论 §十一)"}
|
|
280
294
|
|
|
281
295
|
|
|
296
|
+
# 生效条件:cg 给出时,若 cg.root 下 LOG_FILE 可读,则逐行解析 JSON 并取 .get("conflict_strength"),返回最后一条可解析记录的该键值(缺键或值为 None 则为 None);路径不可用或 OSError 返回 None;
|
|
282
297
|
def _last_strength(cg):
|
|
283
298
|
"""上一条留痕的冲突强度(二阶差分的基线)。流式读,不载全量。"""
|
|
284
299
|
p = os.path.join(cg.root, LOG_FILE)
|
|
@@ -304,6 +319,7 @@ def _last_strength(cg):
|
|
|
304
319
|
# L2 递归反思(受深度 / 节点数 / 循环 / 增益门槛约束)
|
|
305
320
|
# --------------------------------------------------------------------------
|
|
306
321
|
|
|
322
|
+
# 生效条件:以 cg 节点图、seeds 中非空项为初始 frontier、tw_pos/tw_neg 词权,在 d=1..int(max_depth) 每轮先判 frontier 空返回 frontier_exhausted,再逐 nid 处理时若 nodes_visited > max_nodes 先返回 node_budget(可先于同层 discriminators),否则处理完该层后有 discriminators(非 seed_set 节点声明条件与 tw_pos/tw_neg 覆盖 >= CLASH_HIGH)返回 resolved,否则 last_gain < min_gain 返回 gain_below_threshold,循环耗尽返回 depth_exceeded;seeds 假值时 frontier 空,在 d=1 进入循环后由首判返回 frontier_exhausted(depth=0);
|
|
307
323
|
def _recursive_reflect(cg, seeds, tw_pos, tw_neg, max_depth=MAX_DEPTH,
|
|
308
324
|
max_nodes=MAX_NODES, min_gain=MIN_GAIN):
|
|
309
325
|
"""递归反思:沿关系链找「区分条件」,每层检查信息增益。
|
|
@@ -366,6 +382,7 @@ def _recursive_reflect(cg, seeds, tw_pos, tw_neg, max_depth=MAX_DEPTH,
|
|
|
366
382
|
# 主入口:三级决策
|
|
367
383
|
# --------------------------------------------------------------------------
|
|
368
384
|
|
|
385
|
+
# 生效条件:以 cg.index.nodes 为既有节点、content(假值按 "")经 _new_terms 得 pos/neg 并算 tw_pos/tw_neg,按循环中 hard(自否定或纪律命中)→ divergences(同条件槽且 concl < CONCLUSION_SAME)→ strength ≥ CLASH_HIGH → strength ≥ CLASH_LOW → comparable==0 且 (pos or neg) → 否则 ACCEPT 的顺序定 verdict;DEFER 且 int(depth)>0 且 emo["bias"] != "approaching" 时调 _recursive_reflect 补 recursion,auto_flywheel 且 verdict∈{REJECT,DEFER,BLINDSPOT} 时加 unresolved_id,最后 log 并返回 rec;
|
|
369
386
|
def check(cg, content, layer=None, condition_space=None,
|
|
370
387
|
non_applicable_conditions=None, tags=None, exclude=None,
|
|
371
388
|
limit=MAX_SCAN, depth=MAX_DEPTH, auto_flywheel=False,
|
|
@@ -554,6 +571,7 @@ def check(cg, content, layer=None, condition_space=None,
|
|
|
554
571
|
return rec
|
|
555
572
|
|
|
556
573
|
|
|
574
|
+
# 生效条件:missing 为假值(None/空容器/空串)返回 "";否则逐项仅取 m.get("need") 真值者,格式化为 `need(why)`(why 缺键用 "",值为 None 则格式化 "None"),以 ";" 连接;
|
|
557
575
|
def _missing_text(missing):
|
|
558
576
|
"""结构化缺口 → 一行文本(作为飞轮的 known_clues)。
|
|
559
577
|
|
|
@@ -567,6 +585,7 @@ def _missing_text(missing):
|
|
|
567
585
|
for m in missing if m.get("need"))
|
|
568
586
|
|
|
569
587
|
|
|
588
|
+
# 生效条件:cg 提供可调用 flywheel_step 时,以 query(假值按空串)前 200 字符、verdict、missing 文本(空则 reason)、conflicts 非 None 则作 detail 否则 missing 调用;结果 dict 的 unresolved_id 真值时返回它,否则回落 id;无 flywheel_step 或异常返回 None;
|
|
570
589
|
def _fire_flywheel(cg, query, verdict, reason, missing, conflicts=None):
|
|
571
590
|
"""把冲突作为「误差」投给知识飞轮,返回 unresolved 条目 id(失败不阻塞写入)。
|
|
572
591
|
|
|
@@ -592,6 +611,7 @@ def _fire_flywheel(cg, query, verdict, reason, missing, conflicts=None):
|
|
|
592
611
|
# 留痕 / 统计 / 自描述
|
|
593
612
|
# --------------------------------------------------------------------------
|
|
594
613
|
|
|
614
|
+
# 生效条件:cg 与 rec 给出时,将 rec 序列化为 JSON 行追加到 cg.root 下 LOG_FILE,OSError 被吞掉,返回 rec;
|
|
595
615
|
def log(cg, rec):
|
|
596
616
|
"""append-only 留痕:每条判定可审计。"""
|
|
597
617
|
p = os.path.join(cg.root, LOG_FILE)
|
|
@@ -603,6 +623,7 @@ def log(cg, rec):
|
|
|
603
623
|
return rec
|
|
604
624
|
|
|
605
625
|
|
|
626
|
+
# 生效条件:cg 给出时,若 cg.root 下 LOG_FILE 可读,则逐行解析 JSON(空行/解析失败跳过);limit 真值时返回 out[-int(limit):][::-1](int(limit)=0 时为全部倒序),limit 为假值(0/None/"")时返回 out[::-1];路径不可用或 OSError 返回 [];
|
|
606
627
|
def history(cg, limit=100):
|
|
607
628
|
"""最近冲突判定留痕(倒序)。"""
|
|
608
629
|
p = os.path.join(cg.root, LOG_FILE)
|
|
@@ -624,6 +645,7 @@ def history(cg, limit=100):
|
|
|
624
645
|
return out[-int(limit):][::-1] if limit else out[::-1]
|
|
625
646
|
|
|
626
647
|
|
|
648
|
+
# 生效条件:逐行 json.loads 计数(不可解析行跳过、OSError 忽略、路径缺失则计数为 0),每行 total 加 1 并按 r.get("verdict")(缺键即 None 键)与 emotional.bias 为真值时的 b 累加,返回 {'records','by_verdict','by_bias','max_scan','max_depth','min_gain'},后三者取模块常量 MAX_SCAN/MAX_DEPTH/MIN_GAIN;
|
|
627
649
|
def summary(cg):
|
|
628
650
|
"""冲突面汇总(流式计数,供 health 审计)。"""
|
|
629
651
|
p = os.path.join(cg.root, LOG_FILE)
|
|
@@ -652,6 +674,7 @@ def summary(cg):
|
|
|
652
674
|
"min_gain": MIN_GAIN}
|
|
653
675
|
|
|
654
676
|
|
|
677
|
+
# 生效条件:无 required 形参,调用即返回引用 EMO_AVOID/EMO_APPROACH、VERDICTS、CLASH_HIGH/CLASH_LOW、SAME_COND_HIGH/SLOT_HIGH/CONCLUSION_SAME、MAX_DEPTH/MAX_NODES/MIN_GAIN 等模块级常量的自描述字典;
|
|
655
678
|
def catalog():
|
|
656
679
|
"""自描述:三级决策 + 四态 + 递归约束(供 MCP / 文档对照验证)。"""
|
|
657
680
|
return {
|
|
@@ -692,4 +715,4 @@ def catalog():
|
|
|
692
715
|
"discipline_detection": {"tags": list(DISCIPLINE_TAGS),
|
|
693
716
|
"id_prefixes": ["discipline_", "work_discipline"]},
|
|
694
717
|
"honest_boundary": "条件级(结构化)冲突检测,非语义蕴含证明;无法比对时 BLINDSPOT",
|
|
695
|
-
}
|
|
718
|
+
}
|