- commit
- 6f7caa7
- parent
- 4c794d4
- author
- im_wower
- date
- 2026-04-01 09:54:52 +0800 CST
integration: 方案C落板——文件级merge方案(核B壳A)
7 files changed,
+286,
-0
Raw patch view.
1diff --git a/MERGE_PLAN.md b/MERGE_PLAN.md
2new file mode 100644
3index 0000000000000000000000000000000000000000..a253bcb83d624884fea90609f3feb0da711e1811
4--- /dev/null
5+++ b/MERGE_PLAN.md
6@@ -0,0 +1,198 @@
7+# CIE-Unified 整合方案
8+
9+> 日期: 2026-03-31
10+> 决策依据: Branch A 6/8, Branch B 8/8 (同一 cie-datasets formal dataset)
11+> 策略: 方案 C — 核取 B,壳取 A
12+
13+---
14+
15+## 0. 冻结点
16+
17+| 分支 | Commit | 状态 |
18+|------|--------|------|
19+| `branch-a/task04-validation-reporting` | `419ae8d` | 冻结,不再改 |
20+| `branch-b` | `c734288` | 冻结,不再改 |
21+| `review/branch-b-formal-dataset-strict-rerun` | `c110916` | 参考(B 的 strict rerun 验证) |
22+| `review/branch-a-formal-dataset-strict-rerun` | `273f416` | 参考(A 的 strict rerun 验证) |
23+
24+---
25+
26+## 1. 文件级合并计划
27+
28+### 核 — 取 Branch B
29+
30+这些文件直接从 `branch-b @ c734288` 复制,构成 runtime 内核:
31+
32+| 文件 | 来源 | 关键机制 |
33+|------|------|---------|
34+| `cie/graph.py` | **Branch B** | 非对称图(fwd_weight ≠ bwd_weight)、`laplacian_at()`、`asymmetry_at()`、`circulation()`、`convergence()` |
35+| `cie/dynamics.py` | **Branch B** | L_G φ 扩散 + soft clamp、自适应衰减 α(x)=α₀·(1-c)^β·(1/κ)、动态锚点阈值(10th percentile)、三级归巢、置信度自然衰减 |
36+| `cie/state.py` | **Branch B 为基底,吸收 A 的 Profile** | (φ,μ,J) 三元组、AttentionPool、Dirichlet K=3 置信度。**需要吸收 A 的 `SedimentationProfile` dataclass(见下)** |
37+| `cie/runtime.py` | **Branch B 为基底,吸收 A 的信号队列** | CIERuntime 六接口、action_release u=o·c·ε、feedback_loop。**需要吸收 A 的 `PendingSignal` 机制(见下)** |
38+
39+### 壳 — 取 Branch A
40+
41+这些工程设施从 `branch-a @ 419ae8d` 移植到整合分支:
42+
43+| 设施 | 来源 | 说明 |
44+|------|------|------|
45+| `PendingSignal` 信号队列 | **Branch A** `cie/state.py` + `cie/runtime.py` | 将输入/反馈/回灌统一为信号对象排队,下一步 step 时消费。替换 Branch B 的直接 `_feedback_loop()` 调用 |
46+| `SedimentationProfile` | **Branch A** `cie/state.py` | 每节点生命周期对象(stage, activation_hits, stable_steps, dormant_steps, resonance, candidate_score, merged_into)。替换 Branch B 的 `experience_hits` 计数器 |
47+| `cie/validation.py` | **Branch A** `cie/validation.py` | 476 行标准化验证框架,输出 JSON + Markdown 报告。需适配 Branch B 的 snapshot 字段 |
48+| 报告模板 | **Branch A** `reports/` 目录结构 | JSON schema + Markdown 自动生成 |
49+
50+### 不要的
51+
52+| 项目 | 原分支 | 原因 |
53+|------|--------|------|
54+| Branch A 的对称图 `graph.py` | A | 被 B 的非对称图替代 |
55+| Branch A 的 `confidence_proxy` | A | 被 B 的 Dirichlet 替代 |
56+| Branch A 的 age-based 衰减 | A | 被 B 的自适应衰减替代 |
57+| Branch B 的手写 `STAGE_REPORT.md` | B | 被 A 的 validation.py 自动报告替代 |
58+| 两边各自的魔法数字 | A+B | 统一为参数类 `CIEConfig` |
59+| Branch B 的 `HANDOFF.md` | B | 开发阶段文档,不进主干 |
60+
61+---
62+
63+## 2. 接口对齐
64+
65+Branch A 和 B 的六接口签名已基本一致(SPEC §5),需要统一的是内部实现路径:
66+
67+```
68+ingest(input, context, anchors)
69+ → 创建 PendingSignal(来自 A 的模式)
70+ → 排入 state.pending_signals
71+
72+step(n)
73+ → 消费 pending_signals → _apply_signal()(A 的队列消费)
74+ → _propagate_activation()(B 的 L_G 扩散 + 激活传播)
75+ → _apply_homing()(B 的三级归巢)
76+ → _apply_decay()(B 的自适应衰减)
77+ → _refresh_sedimentation()(A 的 SedimentationProfile 检测 + B 的阈值)
78+ → _refresh_observability()
79+
80+emit()
81+ → action_release u=o·c·ε(B 的公式)
82+ → 创建 feedback PendingSignal(A 的模式)
83+
84+commit_feedback(feedback)
85+ → 创建 feedback PendingSignal with polarity(A 的模式)
86+ → 包含 weaken_confidence(B 的 Dirichlet 衰减)
87+
88+snapshot_state()
89+ → 所有 SPEC §6 字段(A+B 已对齐)
90+
91+reset_session()
92+ → 清激活/注意力,保留 φ/ability_cores/anchors(B 的逻辑)
93+```
94+
95+---
96+
97+## 3. 合并顺序
98+
99+**原则:先壳接核,不同时大改理论和工程外壳。**
100+
101+### Phase 1: 基底搭建(Day 1)
102+
103+1. 从 `branch-b @ c734288` 复制 `cie/graph.py`、`cie/dynamics.py`、`cie/state.py`、`cie/runtime.py`
104+2. 跑 Branch B 的 42 项测试确认基底不坏
105+3. 提交:`integration: 基底——Branch B runtime 核心`
106+
107+### Phase 2: 信号队列移植(Day 1-2)
108+
109+1. 从 Branch A 移植 `PendingSignal` dataclass 到 `cie/state.py`
110+2. 改写 `runtime.py` 的 `ingest()`、`emit()`、`commit_feedback()` 使用信号队列
111+3. 改写 `_feedback_loop()` 为 `_apply_signal()` 的队列消费
112+4. 跑测试确认回灌/反馈功能不退化
113+5. 提交:`integration: 信号队列——PendingSignal 替换直接调用`
114+
115+### Phase 3: 沉积 Profile 移植(Day 2)
116+
117+1. 从 Branch A 移植 `SedimentationProfile` dataclass 到 `cie/state.py`
118+2. 改写 `dynamics.py` 的 `sediment()` 使用 Profile(保留 B 的滑动窗口 + 动态阈值)
119+3. 在 snapshot_state 中输出 Profile 信息
120+4. 跑测试确认沉积路径功能不退化
121+5. 提交:`integration: 沉积 Profile——SedimentationProfile 替换 experience_hits`
122+
123+### Phase 4: 参数统一(Day 2)
124+
125+1. 创建 `cie/config.py`,把两边散落的魔法数字收集为 `CIEConfig` dataclass
126+2. `CIERuntime.__init__` 接收 `config: CIEConfig`
127+3. 提交:`integration: 参数统一——CIEConfig 替换魔法数字`
128+
129+### Phase 5: 验证框架移植(Day 3)
130+
131+1. 从 Branch A 移植 `cie/validation.py`
132+2. 适配 Branch B 的 snapshot 字段(已基本对齐)
133+3. 添加 Branch B 特有的检查项:非对称比、环流、Dirichlet 分化
134+4. 跑 validation,生成 JSON + Markdown 报告
135+5. 提交:`integration: 验证框架——validation.py 适配整合 runtime`
136+
137+### Phase 6: 正式数据集全量验证(Day 3)
138+
139+1. 用 `/Users/george/code/cie-datasets` 的 hydrated JSONL 跑完整 8 场景验证
140+2. 生成正式报告
141+3. 与 Branch A 6/8 和 Branch B 8/8 做三方对比
142+4. 提交:`integration: 正式验证——cie-datasets 8 场景`
143+
144+---
145+
146+## 4. 验收标准
147+
148+整合完成后必须满足:
149+
150+| # | 标准 | 来源 |
151+|---|------|------|
152+| 1 | SPEC §9 全部 11 项 | LOCKED_IMPLEMENTATION_SPEC |
153+| 2 | Branch B 的 42 项测试全通 | branch-b tests |
154+| 3 | Branch A 的 18 项测试逻辑等价全通 | branch-a tests(适配后) |
155+| 4 | cie-datasets 8 场景全 PASS | formal_validation |
156+| 5 | phi 不超 ±10.1(soft clamp 保留) | 数值稳定性 |
157+| 6 | 非对称比能涌现词结构 | word_emergence 验证 |
158+| 7 | validation.py 自动生成 JSON + MD 报告 | 工程要求 |
159+| 8 | 无魔法数字,全部在 CIEConfig 中 | 可维护性 |
160+
161+---
162+
163+## 5. 风险
164+
165+| 风险 | 影响 | 缓解 |
166+|------|------|------|
167+| PendingSignal 移植引入延迟回灌 bug | 回灌检测失败 | Phase 2 立即跑 smoke test 02 |
168+| SedimentationProfile 与 B 的衰减/阈值不兼容 | 沉积路径退化 | Phase 3 跑 dynamics test 03-05 |
169+| A 的 validation.py 假设 A 的 snapshot 格式 | 字段不匹配 | Phase 5 逐字段适配 |
170+| 合并后数值行为微变 | 原有测试值不完全匹配 | 允许 ±5% 浮点容差 |
171+
172+---
173+
174+## 6. 时间估计
175+
176+| Phase | 预计耗时 |
177+|-------|---------|
178+| Phase 1 基底 | 30 分钟 |
179+| Phase 2 信号队列 | 2 小时 |
180+| Phase 3 沉积 Profile | 1.5 小时 |
181+| Phase 4 参数统一 | 1 小时 |
182+| Phase 5 验证框架 | 1.5 小时 |
183+| Phase 6 全量验证 | 1 小时 |
184+| **总计** | **~7.5 小时** |
185+
186+---
187+
188+## 7. 决策记录
189+
190+**方案 C 落板依据:**
191+
192+| 事实 | 数据 |
193+|------|------|
194+| Branch B formal dataset | **8/8 PASS**(独立复现) |
195+| Branch A formal dataset | **6/8 PASS**(初中数学 phi=12.07 超限,跨学科 phi=20.18 超限) |
196+| Branch A raw 五本课本 | 8/10(更早轮次) |
197+| Branch B 理论贴合 | 三核量 (o,c,ω) 全实现 |
198+| Branch A 工程壳 | PendingSignal + SedimentationProfile + validation.py |
199+
200+**核取 B 的理由**:非对称图/L_G/Dirichlet/circulation 是 README 理论主线的忠实实现,丢掉等于放弃 CIE 核心;Branch A 在稳定性上也不如 B(两个场景 phi 超限)。
201+
202+**壳取 A 的理由**:信号队列模式比直接调用更规整;SedimentationProfile 比计数器更精细;validation.py 自动报告是工程必需品。
203+
204+**三方共识**:George(决策者)、ChatGPT(Branch A 开发者/审查者)、Claude(Branch B 开发者/审查者)均同意方案 C。
205diff --git a/cie/__pycache__/__init__.cpython-310.pyc b/cie/__pycache__/__init__.cpython-310.pyc
206new file mode 100644
207index 0000000000000000000000000000000000000000..88cf0a484e070af7f8ed7ecf56c1214090c10242
208Binary files /dev/null and b/cie/__pycache__/__init__.cpython-310.pyc differ
209diff --git a/cie/__pycache__/dynamics.cpython-310.pyc b/cie/__pycache__/dynamics.cpython-310.pyc
210new file mode 100644
211index 0000000000000000000000000000000000000000..35fdb5c1644169e05af271bef9677e07ed9d40a4
212Binary files /dev/null and b/cie/__pycache__/dynamics.cpython-310.pyc differ
213diff --git a/cie/__pycache__/graph.cpython-310.pyc b/cie/__pycache__/graph.cpython-310.pyc
214new file mode 100644
215index 0000000000000000000000000000000000000000..1015b58ab49777a452f9704b801e330e2524a8ff
216Binary files /dev/null and b/cie/__pycache__/graph.cpython-310.pyc differ
217diff --git a/cie/__pycache__/runtime.cpython-310.pyc b/cie/__pycache__/runtime.cpython-310.pyc
218new file mode 100644
219index 0000000000000000000000000000000000000000..a12da98775e997d65b8a6ce80e2af8110b2be479
220Binary files /dev/null and b/cie/__pycache__/runtime.cpython-310.pyc differ
221diff --git a/cie/__pycache__/state.cpython-310.pyc b/cie/__pycache__/state.cpython-310.pyc
222new file mode 100644
223index 0000000000000000000000000000000000000000..762f4b591fd98d399aa547b13532c982cdc23178
224Binary files /dev/null and b/cie/__pycache__/state.cpython-310.pyc differ
225diff --git a/tests/formal_validation.py b/tests/formal_validation.py
226new file mode 100644
227index 0000000000000000000000000000000000000000..e8f434156c3896b78ddcaced53bfc25b4d3095cb
228--- /dev/null
229+++ b/tests/formal_validation.py
230@@ -0,0 +1,88 @@
231+import sys, os, json, math, time
232+sys.path.insert(0, "/Users/george/code/CIE-Unified")
233+from cie import CIERuntime
234+
235+DS = "/Users/george/code/cie-datasets/china_text_book_md/v2026-03-28"
236+
237+def load_recs(stage, subject, n=80):
238+ path = os.path.join(DS, "splits", "by_stage_subject", stage, f"{subject}.jsonl")
239+ recs = []
240+ if not os.path.exists(path): return recs
241+ with open(path) as f:
242+ for line in f:
243+ rec = json.loads(line)
244+ if not rec.get("is_content"): continue
245+ t = rec.get("text","")
246+ if len(t) >= 4: recs.append(t)
247+ if len(recs) >= n: break
248+ return recs
249+
250+combos = [("小学","语文"),("小学","数学"),("初中","语文"),("初中","数学"),("高中","语文")]
251+tests = []
252+
253+# Pipeline + Stability per combo
254+for stage, subj in combos:
255+ label = stage + subj
256+ recs = load_recs(stage, subj, 80)
257+ if not recs:
258+ tests.append({"name": label, "status": "FAIL", "detail": "no data"})
259+ continue
260+ rt = CIERuntime(seed=42)
261+ t0 = time.time()
262+ for r in recs:
263+ rt.ingest(r[:60])
264+ rt.step(n=1)
265+ elapsed = time.time() - t0
266+ ot = rt.emit()
267+ if ot["activated"]:
268+ rt.commit_feedback({"correct": [ot["activated"][0]["node"]], "reward": 1.0})
269+ snap = rt.snapshot_state()
270+ ok = snap["phi_summary"]["count"] > 20 and abs(snap["phi_summary"]["max"]) <= 10.1
271+ ok &= snap["attention"]["used"] <= snap["attention"]["total"] + 0.01
272+ ok &= all(math.isfinite(v) for v in rt.state.phi.values())
273+
274+ # Emergence: top words
275+ g = rt.graph
276+ cn_bg = []
277+ for se in g.fwd_edges.values():
278+ for dst, edge in se.items():
279+ if "\u4e00" <= edge.src <= "\u9fff" and "\u4e00" <= dst <= "\u9fff":
280+ bwd = g.get_bwd_weight(edge.src, dst)
281+ ratio = edge.weight / bwd if bwd > 0.01 else edge.weight * 100
282+ cn_bg.append((edge.src+dst, round(ratio,1)))
283+ cn_bg.sort(key=lambda x: -x[1])
284+
285+ d = f"n={snap['phi_summary']['count']}, e={snap['graph']['edge_count']}, phi=[{snap['phi_summary']['min']:.3f},{snap['phi_summary']['max']:.3f}], mode={ot['mode']}, t={elapsed:.1f}s, words={cn_bg[:5]}"
286+ tests.append({"name": label, "status": "PASS" if ok else "FAIL", "detail": d})
287+
288+# Cross-stage
289+rt2 = CIERuntime(seed=42)
290+for stage in ["小学","初中","高中"]:
291+ for r in load_recs(stage, "语文", 30):
292+ rt2.ingest(r[:50])
293+ rt2.step(n=1)
294+s2 = rt2.snapshot_state()
295+ok2 = abs(s2["phi_summary"]["max"]) <= 10.1 and s2["phi_summary"]["count"] > 30
296+tests.append({"name": "cross_stage", "status": "PASS" if ok2 else "FAIL",
297+ "detail": f"n={s2['phi_summary']['count']}, phi={s2['phi_summary']['max']:.3f}"})
298+
299+# Cross-subject
300+rt3 = CIERuntime(seed=42)
301+for subj in ["语文","数学","科学"]:
302+ for r in load_recs("小学", subj, 30):
303+ rt3.ingest(r[:50], anchors=[subj])
304+ rt3.step(n=1)
305+s3 = rt3.snapshot_state()
306+ok3 = abs(s3["phi_summary"]["max"]) <= 10.1
307+tests.append({"name": "cross_subject", "status": "PASS" if ok3 else "FAIL",
308+ "detail": f"n={s3['phi_summary']['count']}, phi={s3['phi_summary']['max']:.3f}, cores={len(rt3.state.ability_cores)}"})
309+
310+# Summary
311+passed = sum(1 for t in tests if t["status"]=="PASS")
312+failed = sum(1 for t in tests if t["status"]=="FAIL")
313+for t in tests:
314+ print(f"[{t['status']}] {t['name']}: {t['detail']}")
315+print(f"\n总计: {passed}/{len(tests)} PASS")
316+
317+with open("/tmp/formal_val_results.json", "w") as f:
318+ json.dump({"tests": tests, "summary": {"passed": passed, "failed": failed, "total": len(tests), "dataset": DS}}, f, ensure_ascii=False, indent=2, default=str)