depa-codument 0.4.1

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.
Files changed (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +262 -0
  3. package/package.json +63 -0
  4. package/src/cli/commands/archive.ts +519 -0
  5. package/src/cli/commands/decisions.ts +123 -0
  6. package/src/cli/commands/engineering.ts +105 -0
  7. package/src/cli/commands/init.ts +54 -0
  8. package/src/cli/commands/list.ts +73 -0
  9. package/src/cli/commands/modeling.ts +105 -0
  10. package/src/cli/commands/show.ts +238 -0
  11. package/src/cli/commands/status.ts +140 -0
  12. package/src/cli/commands/upgrade-track.ts +385 -0
  13. package/src/cli/commands/upgrade-workspace.ts +138 -0
  14. package/src/cli/commands/validate.ts +330 -0
  15. package/src/cli/engineering/config.ts +68 -0
  16. package/src/cli/engineering/lint.ts +58 -0
  17. package/src/cli/engineering/merge.ts +172 -0
  18. package/src/cli/engineering/registry.ts +230 -0
  19. package/src/cli/engineering/schema.ts +126 -0
  20. package/src/cli/engineering/validate.ts +286 -0
  21. package/src/cli/index.ts +136 -0
  22. package/src/cli/modeling/config.ts +68 -0
  23. package/src/cli/modeling/lint.ts +58 -0
  24. package/src/cli/modeling/merge.ts +172 -0
  25. package/src/cli/modeling/registry.ts +229 -0
  26. package/src/cli/modeling/schema.ts +160 -0
  27. package/src/cli/modeling/validate.ts +282 -0
  28. package/src/cli/utils/index.ts +941 -0
  29. package/src/cli/utils/install.ts +291 -0
  30. package/src/cli/utils/spec-xml.ts +673 -0
  31. package/src/cli/utils/track-time.ts +75 -0
  32. package/src/cli/utils/vfs.ts +102 -0
  33. package/src/templates/codument/README.md +59 -0
  34. package/src/templates/codument/attractors/product.md +17 -0
  35. package/src/templates/codument/attractors/project.md +10 -0
  36. package/src/templates/codument/backlog/README.md +33 -0
  37. package/src/templates/codument/config/attractor-profiles.xml +31 -0
  38. package/src/templates/codument/config/engineering.xml +22 -0
  39. package/src/templates/codument/config/modeling.xml +22 -0
  40. package/src/templates/codument/config/operation-hooks.xml +55 -0
  41. package/src/templates/codument/memory/README.md +13 -0
  42. package/src/templates/codument/missions/README.md +125 -0
  43. package/src/templates/codument/sop/README.md +14 -0
  44. package/src/templates/codument/std/AGENTS.md +82 -0
  45. package/src/templates/codument/std/attractors/depa-attractor.md +572 -0
  46. package/src/templates/codument/std/attractors/knowledge-tiers.md +128 -0
  47. package/src/templates/codument/std/attractors/model-driven-docs.md +293 -0
  48. package/src/templates/codument/std/attractors/project-memory.md +48 -0
  49. package/src/templates/codument/std/docs-impl-fractal/index.md +110 -0
  50. package/src/templates/codument/std/docs-modeling-fractal/index.md +156 -0
  51. package/src/templates/codument/std/kernel-pointer.md +19 -0
  52. package/src/templates/codument/std/operations/README.md +30 -0
  53. package/src/templates/codument/std/operations/_operation-spec.md +41 -0
  54. package/src/templates/codument/std/operations/archive-mission.md +66 -0
  55. package/src/templates/codument/std/operations/archive-track.md +238 -0
  56. package/src/templates/codument/std/operations/artifact-sync.md +172 -0
  57. package/src/templates/codument/std/operations/discuss-phase.md +214 -0
  58. package/src/templates/codument/std/operations/discuss.md +87 -0
  59. package/src/templates/codument/std/operations/docs-bootstrap.md +148 -0
  60. package/src/templates/codument/std/operations/gap-loop.md +301 -0
  61. package/src/templates/codument/std/operations/impl-mission.md +167 -0
  62. package/src/templates/codument/std/operations/impl-quick.md +79 -0
  63. package/src/templates/codument/std/operations/impl-track.md +537 -0
  64. package/src/templates/codument/std/operations/migrate.md +337 -0
  65. package/src/templates/codument/std/operations/plan-mission.md +230 -0
  66. package/src/templates/codument/std/operations/plan-track-wave.md +231 -0
  67. package/src/templates/codument/std/operations/plan-track.md +579 -0
  68. package/src/templates/codument/std/operations/revise-track.md +136 -0
  69. package/src/templates/codument/std/operations/validate.md +339 -0
  70. package/src/templates/codument/std/operations/verify.md +184 -0
  71. package/src/templates/codument/std/root-agents.md +39 -0
  72. package/src/templates/codument/std/sop/questioning.md +98 -0
  73. package/src/templates/codument/std/sop/tdd.md +26 -0
  74. package/src/templates/codument/std/sop/validation.md +25 -0
  75. package/src/templates/codument/std/sop/wave-exec.md +42 -0
  76. package/src/templates/codument/std/sop/workflow.md +35 -0
  77. package/src/templates/codument/std/spec/behavior-delta.md +36 -0
  78. package/src/templates/codument/std/spec/behavior-registry.md +42 -0
  79. package/src/templates/codument/std/spec/engineering-delta.md +68 -0
  80. package/src/templates/codument/std/spec/engineering-node-schema.md +86 -0
  81. package/src/templates/codument/std/spec/engineering-registry.md +82 -0
  82. package/src/templates/codument/std/spec/flow-notation.md +93 -0
  83. package/src/templates/codument/std/spec/folder-manifest.md +99 -0
  84. package/src/templates/codument/std/spec/mission-xml-spec.md +249 -0
  85. package/src/templates/codument/std/spec/modeling-delta.md +85 -0
  86. package/src/templates/codument/std/spec/modeling-node-schema.md +183 -0
  87. package/src/templates/codument/std/spec/modeling-registry.md +49 -0
  88. package/src/templates/codument/std/spec/track-xml-spec.md +272 -0
  89. package/src/templates/codument/std/spec/xnl-format.md +301 -0
  90. package/src/templates/codument/workflows/README.md +15 -0
  91. package/src/templates/manifest.ts +177 -0
  92. package/src/templates/skills/README.md +38 -0
  93. package/src/templates/skills/codument-archive/SKILL.md +17 -0
  94. package/src/templates/skills/codument-archive-mission/SKILL.md +17 -0
  95. package/src/templates/skills/codument-archive-track/SKILL.md +17 -0
  96. package/src/templates/skills/codument-artifact-sync/SKILL.md +17 -0
  97. package/src/templates/skills/codument-code-quality-score/SKILL.md +67 -0
  98. package/src/templates/skills/codument-decision-tree/SKILL.md +40 -0
  99. package/src/templates/skills/codument-discuss/SKILL.md +17 -0
  100. package/src/templates/skills/codument-discuss-phase/SKILL.md +17 -0
  101. package/src/templates/skills/codument-docs-bootstrap/SKILL.md +17 -0
  102. package/src/templates/skills/codument-gap-loop/SKILL.md +17 -0
  103. package/src/templates/skills/codument-impl-mission/SKILL.md +17 -0
  104. package/src/templates/skills/codument-impl-quick/SKILL.md +17 -0
  105. package/src/templates/skills/codument-impl-track/SKILL.md +17 -0
  106. package/src/templates/skills/codument-implement/SKILL.md +14 -0
  107. package/src/templates/skills/codument-migrate/SKILL.md +17 -0
  108. package/src/templates/skills/codument-modeling-engineering-e2e/SKILL.md +74 -0
  109. package/src/templates/skills/codument-plan-mission/SKILL.md +17 -0
  110. package/src/templates/skills/codument-plan-track/SKILL.md +17 -0
  111. package/src/templates/skills/codument-plan-track-wave/SKILL.md +17 -0
  112. package/src/templates/skills/codument-revise-track/SKILL.md +17 -0
  113. package/src/templates/skills/codument-track/SKILL.md +14 -0
  114. package/src/templates/skills/codument-validate/SKILL.md +17 -0
  115. package/src/templates/skills/codument-verify/SKILL.md +17 -0
  116. package/src/types/text-assets.d.ts +9 -0
  117. package/src/version.ts +1 -0
@@ -0,0 +1,572 @@
1
+ # DEPA 架构吸引子(DEPA Architecture Attractor)
2
+
3
+ > 这份文档定义一个采用 DEPA 思想(**D**ata / **E**ffect / **P**rocessor / **A**ctor)的项目**应当长期收敛到的稳定结构**。它不是清单、不是路线图、不是允许范围的边界,而是用**少数高层不变量**隐式定义的吸引子:局部实现可以千变万化,整体始终被这些关系拉回同一类形状。像"定义流形的方程"——不预先写出每个合法点,只规定哪些关系必须成立;满足关系的代码自然落进同一结构。
4
+ >
5
+ > **三层区分**:吸引子本体 = §3 的硬不变量;本文件 = 吸引子的**载体**(可版本化、可审计);代码 = 吸引子的**瞬时投影**。三者不冲突——问"当前行为如何"以代码为准,问"该收敛到哪"以本文件为准,问"为什么弃某路"以分析/日志为准。
6
+
7
+ ---
8
+
9
+ ## 0. 怎么用这份吸引子
10
+
11
+ - **它做什么**:规定 DEPA 项目里哪些原语合法、哪些依赖方向合法、哪些 owner 边界不可破、哪些老结构已不属于正确状态空间。它的价值不是描述一切,而是**让错误结构无法合法存续**。
12
+ - **它不做什么**:不枚举每个正确实现,不替代代码/类型/测试做"当前行为"的事实源,不充当任务清单。一次违反未必立刻报错,但**持续偏离会腐蚀结构**——吸引子治的是"扰动下的稳定性",不是"越界即错"的护栏。
13
+ - **优先级边界**:技术结构与跨模块规则以本文件为准;单次行为语义以代码/类型/测试为准;持久化 / schema 真相以真实 model/schema 文件为准。
14
+ - **判据不是库**:DEPA 的参照实现可以是某些 data-graph / processor / actor / 标准组件库,但判据是**维度与不变量**,不是这些库。任何语言、任何技术栈,只要满足下面的关系,就落在吸引子里。
15
+
16
+ ---
17
+
18
+ ## 1. 一句话吸引子(the equation)
19
+
20
+ 一个 DEPA 系统收敛到这组相互定义的关系上:
21
+
22
+ ```text
23
+ output = fn(runtime, input, config) 逻辑是纯函数:依赖显式注入、副作用分离
24
+ runtime = 数据(大部分) + effect 契约(少部分) + actor 依赖(复杂时) 是载体,不写逻辑
25
+ state = fold(reducer, events) 状态是事件的投影:单一写入者、衍生不反写
26
+ process = 数据血缘(D) 串 纯处理器(P) 标准封装;分发用注册表,不用 if/elif 长链
27
+ 协作 = 同步 command / 异步 message 跨边界、等外部、要调度的走 mailbox
28
+ 依赖 = 单向无环 出现环 / 共享可变状态 → 把一节点 actor 化
29
+ 组织 = capsule 单入口、internals 隐藏、对外只暴露稳定契约
30
+ 复杂度 = 由真实需求驱动 vendor 原语优先,不为"将来可能"堆抽象
31
+ ```
32
+
33
+ 后面每节把其中一条展开成可判定的形态、信号与排除集。
34
+
35
+ ---
36
+
37
+ ## 2. 基本原语(封闭集)
38
+
39
+ DEPA 的合法"词汇表"是一个封闭集。系统里每个结构都应能映射到其中之一;映射不上的、或自造已有原语的,是漂移信号。
40
+
41
+ | 原语 | 是什么 | 维度 |
42
+ |------|--------|------|
43
+ | **事件 event** | 不可变、追加式、有序的事实记录("发生了什么") | Data |
44
+ | **投影 projection** | 从事件 fold 出的衍生状态(只读、可重建、不反写) | Data |
45
+ | **快照 snapshot** | 可丢弃可重建的中间产物(checkpoint) | Data |
46
+ | **runtime** | 长生命周期依赖与状态的**数据载体**(D 主 + E 少 + A 时含) | D/E/A |
47
+ | **input / config** | 单次调用的 payload / 静态枚举开关 | Effect |
48
+ | **核心逻辑 fn** | `fn(runtime, input, config)` 的纯/async 函数,依赖全来自参数 | Effect |
49
+ | **副作用契约 effect** | "怎么产生副作用"的契约/工厂:声明在 runtime、实现在 impl | Effect |
50
+ | **处理器 / adapter** | 把一份数据映射成另一份数据的纯函数(outer↔inner 转换、core 编排) | Processor |
51
+ | **分发引擎 dispatch** | 枚举 id → handler 的可组合注册表(动态路由时用) | Processor |
52
+ | **command / message** | 同步命令(同栈)/ 异步消息(经 mailbox) | Processor / Actor |
53
+ | **actor + mailbox** | 单一所有权的并发/解环单元,外部经消息读写 | Actor |
54
+ | **capsule** | 单公开入口、internals 隐藏、对外只暴露稳定契约的模块单元 | 组织 |
55
+ | **事实等级 fact-grade** | 数据节点在 7 级阶梯上的位置(权威 → 投影) | 事实源 |
56
+
57
+ ---
58
+
59
+ ## 3. 硬不变量(the invariants)
60
+
61
+ 吸引子的"方程"就是下面这组高层不变量。它们少而硬:局部怎么写都行,但这些关系不能破。结构性的几条给出语言中立的形态对照(`✅` 收敛态 / `❌` 排除态)。
62
+
63
+ ### I1 · 数据与逻辑分离
64
+ 核心逻辑能写成 `output = fn(runtime, input, config)`,依赖全显式、不读全局/单例/`this`,副作用经注入的契约发生。
65
+
66
+ ```text
67
+ ❌ core 读隐式全局、直接 IO
68
+ function handleChat(req) {
69
+ const db = getGlobalDb() // 隐式全局
70
+ logger.info("creating") // 隐式全局
71
+ return db.users.create(req.body) // 直接 IO 写在 core
72
+ }
73
+ ✅ 依赖注入、副作用经契约、core 纯
74
+ function createUser(runtime, input, config) { // fn(runtime,input,config)
75
+ runtime.logger.info("creating") // 注入的契约
76
+ return runtime.db.users.create(input.data)
77
+ }
78
+ ```
79
+
80
+ ### I2 · runtime 是数据载体
81
+ runtime 只装数据与依赖引用,**不写业务方法**。它是 Data(大部分)+ Effect 契约(少部分)+ Actor 依赖(复杂时)三维的共同展开,不专属某一维。
82
+
83
+ ```text
84
+ ❌ runtime 容器内嵌业务方法(数据与逻辑混在一起,无法单测/替换)
85
+ OrderRuntime { orderDb, paymentClient, runCheckout(cart){ ...扣款扣库存写单... } }
86
+ ✅ runtime 纯数据;逻辑外置成以 runtime 为首参的函数
87
+ OrderRuntime { orderDb, paymentClient }
88
+ runCheckout(runtime, cart, config) -> Receipt { ... }
89
+ ```
90
+
91
+ ### I3 · 三参数归位
92
+ 长生命周期/共享/跨步骤状态 → `runtime`;单次 payload → `input`;单次静态枚举/开关 → `config`。
93
+ 破:稳定依赖(registry/client/session)偷渡进 input/config;函数对象塞进 config;config 重复 runtime 已有字段(两处真源必漂移)。
94
+
95
+ ```text
96
+ ❌ 稳定依赖偷渡进 input、函数对象塞 config
97
+ input = { userQuery, dbClient } // dbClient 长生命周期 → 该进 runtime
98
+ config = { onDone: () => {...} } // 函数对象 → 是 effect 契约,该进 runtime
99
+ ✅ 各归其位
100
+ runtime = { dbClient, onDone } // 长生命周期依赖 + 副作用契约
101
+ input = { userQuery } // 单次 payload
102
+ config = { mode: "fast" } // 静态枚举 / 开关
103
+ ```
104
+
105
+ ### I4 · 副作用契约与编排分离
106
+ effect 以契约/工厂声明在 runtime,编排在 factory/bootstrap,core 只调注入的契约;contract / logic / impl 分层、单向依赖(contract ← logic ← impl)。
107
+ 破:contract 文件里写副作用编排;core 直接 import 具体 impl;应用级 registry 只经全局变量传。
108
+
109
+ ```text
110
+ ❌ 契约 + 编排 + impl 糊在一起
111
+ class PaymentContract { charge(a){ new StripeClient(KEY).charge(a) } } // 三者混进契约
112
+ ✅ 契约声明 / 编排在 bootstrap / core 只调契约
113
+ interface PaymentEffect { charge(a): Promise<Receipt> } // 契约:怎么产生
114
+ runtime.payment = makeStripePayment(cfg) // 编排:在 bootstrap 组装
115
+ // core: await runtime.payment.charge(a) // core 只调注入的契约
116
+ ```
117
+
118
+ ### I5 · 单一写入者 + 衍生不反写 + 状态可重建
119
+ 一份数据只有一个权威写入者,**修改只走唯一入口、不散弹式分散改**;同一类事实真相放在接近位置统一维护;投影/缓存/快照只读、不反写上游;允许多份衍生数据,但写入口唯一;当前状态尽量能从事件重放重建。
120
+
121
+ ```text
122
+ ❌ 投影反写源 / 两个半真源同时生效
123
+ cache.set(id, v); writeBackToLog(v) // 投影回写上游,日志与投影脱节
124
+ ✅ 单写 + 发新事件,状态是投影
125
+ appendEvent({ type: "OrderPaid", id }) // 只往 append-only 日志追加
126
+ state = fold(reducer, events) // 当前状态 = 重放事件,只读
127
+ ```
128
+
129
+ ### I6 · 标准封装:数据血缘(D) 与处理器(P) 分列
130
+ 一段调用从 outer 进、回 outer 出,是**一条显式数据血缘**被**一组纯处理器**串起来——数据是名词、处理器是 `data→data` 的纯函数,**两块分开**,绝不在同一格 / 同一无差别箭头链里混(详见 §7)。
131
+ 破:把 `Outer Input → Transform → Core → Outer Output` 这种数据名词与逻辑动词混排,当成"流程图"。
132
+
133
+ ### I7 · 受控分发
134
+ 动态路由用枚举 id → adapter 注册表,新增策略不改已有代码;逻辑固定(Sequence/Selector/Condition)不套分发。
135
+
136
+ ```text
137
+ ❌ if/elif 字符串分发(加一种类型就改这块)
138
+ if (t==="create") return handleCreate(x)
139
+ else if (t==="update") return handleUpdate(x) ...
140
+ ✅ 枚举 id → adapter 注册表(新增不改已有代码)
141
+ registry.get(t)(x) // 未知 id 显式报错,不静默回退
142
+ ```
143
+
144
+ ### I8 · command / message 边界
145
+ 同步、可立即返回、同调用栈的走 command;跨 actor、等外部、需 timeout/retry/cancel/priority 的走 message(经 mailbox)。
146
+ 破:跨边界协作写成同步直调(丢掉排队/调度/恢复);纯本地同步逻辑硬塞进消息队列绕一圈。
147
+
148
+ ```text
149
+ ❌ 跨边界、要等外部,却同步直调
150
+ const r = otherActor.handleNow(req) // 丢掉排队 / 超时 / 恢复能力
151
+ ✅ command(同栈同步)/ message(跨边界异步)
152
+ reducer(state, cmd) // 同步 command:可立即返回
153
+ mailbox.send({ type:"DoWork", req }) // 异步 message:经 mailbox,可 timeout/retry
154
+ ```
155
+
156
+ ### I9 · 依赖单向无环
157
+ 模块/包/数据/控制各层依赖图都应是有向无环图。
158
+
159
+ ```text
160
+ ❌ 隐式 DI 藏环:A import B,B 靠 service locator / 延迟注入反取 A —— 编译器看不见环
161
+ ✅ 本质环 → 把一节点 actor 化:A 向 B 发 message,依赖回到单向 A → B,环替换成显式异步边界
162
+ ```
163
+
164
+ ### I10 · capsule 组织
165
+ 模块对外只有一个稳定入口,internals 隐藏不可外部 import,对外只暴露 public types。
166
+
167
+ ```text
168
+ ✅ capsule 形态
169
+ order/
170
+ core_logic # 唯一对外入口 run_order(input, config) -> OrderOutput
171
+ adapter_registry # 枚举 id → adapter 布线
172
+ internals/ # 私有实现,外部不可 import
173
+ types # 对外稳定契约(OrderInput / OrderOutput)
174
+ 外部只 import { run_order, OrderInput, OrderOutput };多 capsule 依赖呈单向链 A → B → C
175
+ ```
176
+
177
+ ### I11 · 避免过度设计
178
+ 复杂度由当前真实需求驱动,vendor/标准库已有原语优先。
179
+ 破:同构却套空壳透传 adapter;只有一个实现的策略表/抽象基类;"以防万一"无人用的开关;手搓已有的调度/序列化/重试/状态机。
180
+
181
+ ### I12 · 观测优先于猜测
182
+ 每个"X 有问题 / 这样改"的论断都要能指向证据(代码 `path:line` / 运行现象 / 测试);缺证据时不盲猜——先在可观测基座上加观测点 / sink、记录证据,再分析修复,而非临时 print 或用"通常/应该"替代。
183
+
184
+ ### I13 · 框架中立、做机制不做特例
185
+ 底层设计保持通用,不为单个业务场景破坏通用性——**做机制,不做特例**。问题表面只在某个 app/场景出现时,优先找**通用根因**(runtime / provider / prompt 组装 / 持久化 / 协议管线),而非给那个场景打补丁。
186
+ 破:为达成一次验证而限制工具列表 / 硬编码业务名 / 压某请求的上下文 / 改某 provider 行为;为单个 app 在底层加特例分支。
187
+
188
+ ---
189
+
190
+ ## 4. 四维的收敛形态(D / E / P / A)
191
+
192
+ > **为什么切成这四维**:一段处理逻辑要回答四个相互独立的问题——数据怎么组织(结构能否先于逻辑、状态能否从事件重建)、副作用怎么隔离(依赖能否显式注入、逻辑能否纯化)、处理怎么标准(封装是否同构、分发是否受控)、协作怎么解耦(跨边界是否经显式消息、共享状态归谁)。四个问题彼此正交,所以拆成四维分别判,避免"一处对了就以为整体对了"。
193
+ >
194
+ > 四维**正交**:一段代码可以某维符合、另一维违反,各判各的(例:`fn(runtime,input,config)` 干净【Effect 符合】,但分发硬编码成一长串 if-else【Processor 违反】)。
195
+
196
+ ### Data — 数据一等公民
197
+ - **收敛形态**:结构先于逻辑(先定义数据/schema,再实现操作);状态变化记为**追加式事件**;当前状态 = `fold(reducer, events)`,是投影不是第二真相;事件 → reducer → 投影**单向**。
198
+ - **符合信号**:存在独立数据定义层;找得到一条不可变事件序列;状态能重放重建;投影被消费方只读。
199
+ - **违反信号**:状态藏在可变全局/单例就地 mutate;就地改历史(update/delete 历史条目);投影反写真源;逻辑先于结构(数据是操作里长出来的散落字段)。
200
+
201
+ ### Effect — 副作用与逻辑分离
202
+ - **收敛形态**:`output = fn(runtime, input, config)`;依赖经 runtime 显式注入;副作用契约声明在 runtime、真正 IO 在 impl;contract / logic / impl 分层。
203
+ - **符合信号**:签名一眼看全部依赖;runtime 可换 mock 来测;core 只调注入的契约;config 为 null 或纯静态值。
204
+ - **违反信号**:core 读全局/单例/环境变量、现 new client、直接 IO;契约与编排糊在一起;`runtime: { everything: any }` 巨型上下文。
205
+
206
+ ### Processor — 标准封装与受控分发
207
+ - **收敛形态**:所有组件走同一条封装流程(D 血缘 + P 处理器分列,core 是"读入恰好是 (runtime,input,config)"的那个纯处理器);动态路由用可组合分发引擎;command/message 边界清晰。
208
+ - **符合信号**:组件同构、执行路径可预测;core 不做路径解析/错误包装等框架关注点;新增路由不改已有代码。
209
+ - **违反信号**:执行路径各异;硬编码 if/elif 分发;core 处理框架关注点;同步伪装异步或异步硬塞同步。
210
+
211
+ ### Actor — 异步通信与解环
212
+ - **收敛形态**:依赖图出现环、或多模块共享可变状态时,把一节点定义成 actor,用 command/message 协作;单一所有权、经 mailbox 读写、selective receive。
213
+ - **符合信号**:共享态收进单一 owner,外部经消息读写;timeout/retry/cancel/priority 走 message;调度(fiber/task)与身份(actor)分离。
214
+ - **违反信号**:并发任务直接 mutate 共享对象;满屏裸锁糊共享状态替代消息;用隐式 DI 藏循环依赖。
215
+ - actor 首先为**打断环、显式化共享状态所有权**而用,并发只是顺带。
216
+
217
+ ---
218
+
219
+ ## 5. 事实源阶梯与边界(state-truth 结构)
220
+
221
+ "谁是某份数据的唯一真源"是最容易腐蚀、也最承重的结构。吸引子要求每个关键数据节点能被定级、定 owner。
222
+
223
+ **7 级事实阶梯**(高位=权威,低位=投影):
224
+
225
+ ```text
226
+ 1 内存权威态 ← 唯一写入者持有的 live 真相(最高)
227
+ 2 领域规范事件 ← domain canonical event(追加式、不可变)
228
+ 3 控制面状态 ← live 控制流读这里
229
+ 4 追加流水账 ← append-only journal(旁路,不驱动 live)
230
+ 5 检查点快照 ← checkpoint(只在恢复/启动读,不影响 live 控制)
231
+ 6 衍生投影/缓存 ← 可重建、只读、单向、不反写上游
232
+ 7 表层视图 ← UI 控件/选中态(最低,只发 command,不直接改事实)
233
+ ```
234
+
235
+ **边界规则**(破任一即结构漂移):
236
+ - **唯一写入者**:每个节点恰好一个权威 owner;多个半真源同时生效是红灯。
237
+ - **衍生不反写**:低位(6/7)发现"应该改"时发新事件回到高位,不直接改投影再让两边脱节。
238
+ - **持久层不驱动 live**:用快照/journal/文件 mtime/存在性 判 live 运行状态,是越级读取/反写的红灯。
239
+ - **UI 只发命令**:7 级控件不绕过 command/message 直接改 1/3 级事实。
240
+
241
+ **worked 例**:"这个订单流程是否在跑?" → 读 **3 级控制面**(live 内存控制态),**不读** 5 级 checkpoint 文件的 mtime/存在性;checkpoint 只在崩溃恢复/启动时读。把"在不在跑"挂到持久层元信息上,就是把控制真相错放到了 5 级。
242
+
243
+ ---
244
+
245
+ ## 6. runtime 的收敛形态
246
+
247
+ runtime **没有唯一正确形状**——丰俭由人,按业务复杂度在谱系上取一点。吸引子约束的是**不变量**,不是层数/字段名。下面用同一个业务(订单/结算服务)从薄到厚示范。
248
+
249
+ **形态谱系**(可叠加):
250
+ - **A 最小扁平**:几把显式依赖平铺。`OrderRuntime { orderDb, clock, logger }`
251
+ - **B 角色分组**:按角色与生命周期聚合——副作用契约 / 配置 / 外部上下文(请求级只读) / 内部上下文(跨步骤可变) / 数据快照(immutable+mutable)。新增子字段不破坏签名。
252
+ - **C 跨域嵌套**:一个域 runtime 内嵌另一个域 runtime(单向)。`WriteRuntime { read: ReadRuntime, orderDb, eventLog }`
253
+ - **D 响应式衍生**:private 可写源 + public 只读投影,外部只拿 public 只读流。
254
+ - **E 领域分面/组合根**:多领域分面 + 归属表(谁有权写哪块);组合根**只是 carrier**,自己不放业务逻辑。
255
+
256
+ B 形态(最常见的中等复杂度)具体长这样——字段按角色与生命周期聚合,新增依赖往对应聚合里加子字段、签名不变:
257
+
258
+ ```text
259
+ OrderRuntime {
260
+ effects: { makePaymentClient, makeInventoryClient } // 副作用契约 / factory(进程级)
261
+ options: { maxRetries, currency } // 静态配置(默认值,便于演进)
262
+ outerCtx: frozen { tenantId, callerId, requestedAt } // 外部上下文:请求级只读
263
+ innerCtx: mutable { reservedStock, attempt } // 内部上下文:跨步骤可变
264
+ snapshot: { catalog: frozen, cart: mutable } // 数据镜像:不可变 + 可变分开
265
+ }
266
+ ```
267
+
268
+ **跨形态不变量**(A–E 都必须成立):
269
+ 1. 数据不放逻辑(容器里不写执行方法)。
270
+ 2. 显式注入(无隐式全局自取)。
271
+ 3. 三参数归位(runtime / input / config)。
272
+ 4. 可变 / 不可变分清(frozen 外部上下文 vs 可变内部上下文,别互塞)。
273
+ 5. 衍生是衍生、不是第二真源(public 投影/快照可重建、源真唯一)。
274
+ 6. 可演进(聚合字段扩展不破坏签名;但不为"将来可能"提前堆复杂度)。
275
+
276
+ > 选形态看业务复杂度,不看"标准答案":依赖成堆还在扁平平铺 / 可变与不可变混在一起 → 往 B/D 升;三五个依赖却套五层聚合、没订阅需求却引入响应式层 → 往 A/B 降。
277
+
278
+ ---
279
+
280
+ ## 7. 标准组件流程(canonical processing shape)
281
+
282
+ 一段逻辑从 outer 边界进、回 outer 边界出。**数据与处理器两块分列、绝不同格**:
283
+
284
+ **数据血缘(D · 只有数据,名词)**
285
+ ```text
286
+ outer{runtime · input · config} → derived → inner{runtime · input · config}
287
+ → inner output → outer output
288
+ ```
289
+
290
+ **处理器(P · 只有逻辑,每个纯 `data→data`)**
291
+
292
+ | 处理器 | 读入(D) | 产出(D) |
293
+ |--------|-----------|-----------|
294
+ | outer_derived | outer runtime/input/config | derived |
295
+ | inner_runtime | outer runtime/input/config + derived | inner runtime |
296
+ | inner_input | outer runtime/input/config + derived | inner input |
297
+ | inner_config | outer runtime/input/config + derived | inner config |
298
+ | core_logic(业务) | inner runtime/input/config | inner output |
299
+ | output | outer runtime/input/config + derived + inner output | outer output |
300
+
301
+ - **core_logic 无结构特殊性**:它只是"读入恰好是 (runtime,input,config) 规范三元组"的那个处理器;`output=fn(runtime,input,config)` 讲的就是 P(fn) 与 D 分离,封装流程把这套分离重复几次、串成显式血缘。
302
+ - **outer/inner 分层**:除 core 是内层纯业务,其余处理器在外层处理框架级关注点(解析、错误包装、可观测)。
303
+ - **adapter 唯一存在理由**:outer 与 inner runtime 结构不一致时承载转换;同构强造空壳 adapter 是过度设计。
304
+ - **压扁信号**:inner_runtime/input/config 三处理器整段缺失、outer 直接灌进一个大对象方法里现取现算——module 范围最常见的"未封装"。
305
+
306
+ ### 权威参照实现(协议不走样,实现可适配)
307
+
308
+ 下面是标准封装的**通用、可复用参照实现**。它钉死的是**协议**——六个语义阶段都显式存在、顺序固定(`outer{runtime,input,config}` 进,逐步算出 `derived → innerRuntime → innerInput → innerConfig → innerOutput → outerOutput`),数据(D)与处理器(P)分列。这条协议是不走样的那部分;**实现形态可以按语言 / 场景 / 领域适配**(见代码后「适配与边界」)。它是一段**可复用的通用原语**——项目里已有等价实现就直接用、不要重造,也不强制非得长成这个签名。
309
+
310
+ ```java
311
+ public class StdRunComponentLogic {
312
+ public static <TOuterRuntime, TOuterInput, TOuterConfig, TOuterDerived, TOuterOutput,
313
+ TInnerRuntime, TInnerInput, TInnerConfig, TInnerOutput>
314
+ TOuterOutput runByFuncStyleAdapter(
315
+ TOuterRuntime outerRuntime,
316
+ TOuterInput outerInput,
317
+ TOuterConfig outerConfig,
318
+ StdOuterComputedAdapter<TOuterRuntime, TOuterInput, TOuterConfig, TOuterDerived>
319
+ outerDerivedAdapter,
320
+ StdInnerRuntimeAdapter<TOuterRuntime, TOuterInput, TOuterConfig, TOuterDerived, TInnerRuntime>
321
+ innerRuntimeAdapter,
322
+ StdInnerInputAdapter<TOuterRuntime, TOuterInput, TOuterConfig, TOuterDerived, TInnerInput>
323
+ innerInputAdapter,
324
+ StdInnerConfigAdapter<TOuterRuntime, TOuterInput, TOuterConfig, TOuterDerived, TInnerConfig>
325
+ innerConfigAdapter,
326
+ StdInnerLogic<TInnerRuntime, TInnerInput, TInnerConfig, TInnerOutput>
327
+ coreLogicAdapter,
328
+ StdOuterOutputAdapter<TOuterRuntime, TOuterInput, TOuterDerived, TOuterConfig, TInnerOutput, TOuterOutput>
329
+ outputAdapter
330
+ ) {
331
+ // ① 基于输入衍生出额外输入
332
+ TOuterDerived outerDerived = outerDerivedAdapter
333
+ .stdMakeOuterComputed(outerRuntime, outerInput, outerConfig);
334
+ // ② 内部实现的上下文(构造 inner runtime)
335
+ TInnerRuntime innerRuntime = innerRuntimeAdapter
336
+ .stdMakeInnerRuntime(outerRuntime, outerInput, outerConfig, outerDerived);
337
+ // ③ 将外部封装入参转换为内部实现入参
338
+ TInnerInput innerInput = innerInputAdapter
339
+ .stdMakeInnerInput(outerRuntime, outerInput, outerConfig, outerDerived);
340
+ // ④ 内部实现的配置
341
+ TInnerConfig innerConfig = innerConfigAdapter
342
+ .stdMakeInnerConfig(outerRuntime, outerInput, outerConfig, outerDerived);
343
+ // ⑤ 调用内部逻辑,返回内部实现结果(core 只拿 runtime/input/config)
344
+ TInnerOutput innerOutput = coreLogicAdapter
345
+ .stdInnerLogic(innerRuntime, innerInput, innerConfig);
346
+ // ⑥ 将内部结果转换为外部结果
347
+ TOuterOutput outerOutput = outputAdapter
348
+ .stdMakeOuterOutput(outerRuntime, outerInput, outerConfig, outerDerived, innerOutput);
349
+ return outerOutput;
350
+ }
351
+
352
+ // 默认 helper:不需要转换时显式用 null/identity 透传,而不是省略该步
353
+ public static <TOuterRuntime, TOuterInput, TOuterConfig, TOuterDerived>
354
+ TOuterDerived stdMakeNullOuterComputed(
355
+ TOuterRuntime outerRuntime, TOuterInput outerInput, TOuterConfig outerConfig) {
356
+ return null;
357
+ }
358
+
359
+ public static <TOuterRuntime, TOuterInput, TOuterConfig, TOuterDerived, TInnerRuntime>
360
+ TInnerRuntime stdMakeIdentityInnerRuntime(
361
+ TOuterRuntime outerRuntime, TOuterInput outerInput,
362
+ TOuterConfig outerConfig, TOuterDerived outerDerived) {
363
+ return (TInnerRuntime) outerRuntime;
364
+ }
365
+
366
+ public static <TOuterRuntime, TOuterInput, TOuterConfig, TOuterDerived, TInnerConfig>
367
+ TInnerConfig stdMakeIdentityInnerConfig(
368
+ TOuterRuntime outerRuntime, TOuterInput outerInput,
369
+ TOuterConfig outerConfig, TOuterDerived outerDerived) {
370
+ return (TInnerConfig) outerConfig;
371
+ }
372
+ }
373
+ ```
374
+
375
+ **协议层盯三件事**(这部分不走样):① 六个语义阶段都**显式存在**——不准"少接一步"压扁;② 六步顺序**固定不可调换**;③ 不需要转换的步骤用**显式透传**(`stdMakeNull*/stdMakeIdentity*` 或自定义透传 adapter),而不是把这步删掉——"显式空转换"合规、"压扁省略"是 §9 排除态。
376
+
377
+ **适配与边界**(这部分可变,按需调整):
378
+ - **复用优先**:这是通用可复用原语,项目里已有等价封装就直接用、**不要重造**(呼应 I11 vendor 原语优先);也不是必须照此签名实现。
379
+ - **强类型语言**:常按场景做专用封装**抹平泛型**——把那一长串 `TOuter*/TInner*` 在具体场景里固化成实参类型,对外暴露简洁签名。
380
+ - **弱类型语言**:常**精简掉不必要的 adapter 参数**(用默认 / 显式透传 adapter 顶上),只留真正需要转换的那几个。
381
+ - **领域定制**:业务特殊时,可在**保持上面协议语义**的前提下定制流程——按领域特性增减自定义 adapter 类型(如多一个领域校验 / 投影阶段)。变的是 adapter 的种类与数量,不变的是"显式分阶段、D/P 分列、不压扁"。
382
+
383
+ ---
384
+
385
+ ## 8. 合法依赖方向与 owner 边界
386
+
387
+ 吸引子的"方程"很大一部分是**方向**。下面这些方向不可逆。
388
+
389
+ - **事件 → 投影**(单向):投影不反写事件。
390
+ - **contract ← logic ← impl**:core 依赖契约,impl 实现契约;契约不反依赖逻辑/实现,也不在两处重复定义同一类型。
391
+ - **outer → inner**(adapter):可复用组件对调用域无感知;inner 绝不反向 import outer-domain 模块。
392
+ - **capsule 间单向无环**:A 的入口只 import B 的入口 + B 的 public types,链 `A → B → C` 无回边;触对方 `internals` 是红灯。
393
+ - **跨域 runtime 嵌套单向**:写侧内嵌读侧,读侧绝不回指写侧。
394
+ - **本质环 → actor**:切不掉的环把一节点 actor 化、改发消息,把环替换成显式异步边界,而不是用隐式 DI 把环藏进编译器看不见的地方。
395
+
396
+ > **包依赖图就是架构 harness**:用包之间的依赖关系把上面这些方向**显式化、可机检**——架构同构性长在包结构里,避免一个包内长出混乱依赖。新增包、或改动包间依赖,按架构变更严格 review。
397
+
398
+ ---
399
+
400
+ ## 9. 被排除出合法状态空间的结构
401
+
402
+ 吸引子最重要的动作不是列"对的",而是**把错的排除出合法状态空间**——下面这些结构即使"能跑",也已不属于正确结构,发现即漂移、应被收敛掉,而非当成一种合法变体保留。按维度分组。
403
+
404
+ ```text
405
+ 两个最典型的排除态:
406
+ ❌ runtime 万能袋 runtime = { everything: any } // 谁都能摸出任意东西,依赖不可见
407
+ ❌ 多个半真源 内存权威 + 磁盘快照 都被当源同时生效 // 必然漂移,无法判定谁对
408
+ ```
409
+
410
+ **Data**:状态只活内存无可重建源 · 多个半事实源并存 · 先写文件再回读传状态 · 投影与事实纠缠改不动 · 就地改历史。
411
+
412
+ **Effect**:core 直接 IO / 现 new client · 副作用契约与编排糊在一起 · 隐式全局依赖 · 应用级 registry 只经全局变量传 · contract 模块 import 重型副作用实现。
413
+
414
+ **Processor**:if/elif 字符串分发 · 未知 id 静默回退/返回 None · command/message 混用 · 可复用组件对调用域有感知(import outer-domain 分支)· core 处理路径解析/错误码映射等框架关注点。
415
+
416
+ **Actor**:并发任务直接 mutate 共享对象 · 用裸锁糊共享状态替代消息 · 调度与身份纠缠 · 缺 selective receive · 用隐式 DI 藏环。
417
+
418
+ **事实源边界**:checkpoint 读取影响 live 控制 · journal 字段驱动下一步 · UI 状态反向驱动主循环 · 文件 mtime/存在性当运行状态 · 投影反写源 · 快照夹带单次 payload。
419
+
420
+ **分层**:长生命周期对象藏 input/config · 函数对象塞 config · config 重复 runtime 字段 · 业务逻辑写在 runtime 方法里 · 外部 import 触 internals · contract/logic 反向依赖或同契约两处重复定义。
421
+
422
+ **过度设计**:空壳 adapter · 只有一个实现的策略表 · 无人用的"以防万一"开关 · 复杂度由"将来可能"驱动 · 自造已有 vendor 原语。
423
+
424
+ > 这些是"排除集"——审查/收敛时拿它逐条比对,命中即记一条带证据的现象(`path:line`),归到对应维度,定方向后再排序落地。
425
+
426
+ ---
427
+
428
+ ## 10. 架构设计:把系统拉回吸引子
429
+
430
+ 架构工作不是"一次画对终态",而是**一轮轮把偏离的轨迹收敛回吸引子**。一次收敛沿这条脉络走,可在三种范围复用(系统间 / 模块包级 / 同模块级):
431
+
432
+ 1. **第一性提问**:从一个反复出现/难根治的**表象**穿透到**事实源边界问题**(谁是真源、谁在反写、有没有多个半真源),先出问题清单——不先加 guardrail。
433
+ 2. **事实源边界**:把每个关键数据节点**定级**(§5 阶梯)、填**唯一写入者**、做**反写检查**,产出事实链。把"嫌疑"变成"判定"。
434
+ 3. **证据盘点**:每个"X 有问题"的论断都落成带 `path:line` 的证据——节点→等级→owner、读写路径、包边界、事故。
435
+ 4. **设计收敛**:把每个问题映射到结构图(控制面/数据面/扩展面 × 平台/领域/应用层级),产出处置决策 + vendor 原语映射 + 候选改造边界。
436
+ 5. **切片建议**:从收敛候选里筛**第一批可立即落地**的改造,每条可独立执行、可验收,给依赖顺序与**非目标**(不做什么)。超范围的发现登记 backlog,不就地展开。
437
+ 6. **贯穿原则**:观测优先 · 可验证 · 框架中立 · 避免过度设计——贯穿①–⑤。
438
+
439
+ > 关键纪律:**范围与深度受控**——不一次吞掉巨型项目,每次显式声明范围(系统间/包/模块)与深度;**建议不等于改造**——产出方向与依赖顺序,是否落地、怎么落地是另一步。
440
+
441
+ **收敛 micro 例**(一个臃肿 HTTP 入口 → 三层并列 capsule):
442
+
443
+ ```text
444
+ 现状:HTTP router 里塞满 —— 构造 OuterCtx、直接 controller.create、手拼 stream + 协议形状、手包响应
445
+ 问题(定级/定向):传输逻辑与业务编排纠缠(Effect 违反);无单入口、平铺(I10);协议形状散落(分层)
446
+ 目标:web_entry → app_core → engine_capsule 三层 capsule,依赖单向
447
+ web_entry : 只做 HTTP input/transport output 适配(框架级关注点)
448
+ app_core : 传输无关的应用编排 run_app_core(input, config)
449
+ engine_capsule : OuterRuntime → EngineRuntime 底层适配 run_engine(input, config)
450
+ 切片:先抽 app_core(核心编排归位)→ 再下沉协议 output adapter → 最后 web_entry 只剩 HTTP 适配
451
+ ```
452
+
453
+ ---
454
+
455
+ ## 11. 编码:怎么写才落在吸引子里
456
+
457
+ 吸引子是方向,落键是局部动作。**纠偏发生在写之前**:在下面时机自检,命中"排除集"就改,再往下写。
458
+
459
+ | 你正要做… | 一眼问自己 | 落回哪条不变量 |
460
+ |---|---|---|
461
+ | 写带依赖的 handler/service | 能写成 `fn(runtime,input,config)` 吗?依赖都注入了吗? | I1 · I3 · I4 |
462
+ | 设计/扩张 runtime | 往里塞方法了吗?这依赖归 runtime 还是 input/config? | I2 · I3 |
463
+ | 接请求/组件执行流 | core 自己去 outer 掏字段了吗?runtime 在 core 内 new 了吗? | I6 · §7 |
464
+ | 加分发/路由 | 写成 if/elif 长链了吗?固定逻辑硬套分发了吗? | I7 |
465
+ | 管状态/决定谁写谁 | 这份数据谁是唯一写入者?投影反写上游了吗?能从事件重建吗? | I5 · §5 |
466
+ | 判数据真源/能否反写 | 在用快照/journal/mtime 判 live 吗?投影回写了吗? | I5 · §5 |
467
+ | 依赖成环/共享可变状态 | 在用隐式 DI 藏环吗?该 actor 化吗? | I9 |
468
+ | 跨并发/异步协作 | 该 command 还是 message?涉及 timeout/retry 吗? | I8 |
469
+ | 组织模块/包 | 单入口了吗?internals 隐藏了吗?依赖单向吗? | I10 |
470
+ | 想加抽象/框架/开关 | 有第二实现吗?vendor 有原语吗?这开关有人用吗? | I11 |
471
+
472
+ **常驻反射**(不用查表就该守):
473
+
474
+ - `output = fn(runtime, input, config)`:依赖全显式注入,不读全局/单例/`this`;副作用经契约、真正 IO 在 impl。
475
+ - runtime 是数据载体、不写业务方法;长生命周期/共享 → runtime,单次 payload → input,静态枚举/开关 → config。
476
+ - 一份数据一个写入者;衍生只读、不反写上游;状态尽量能从事件重建。
477
+ - 标准封装 + 注册表分发;固定逻辑不套分发/空壳 adapter。
478
+ - 同步 command / 异步 message(跨 actor、等外部、要 timeout/retry/cancel/priority 的走 mailbox)。
479
+ - 依赖成环或共享可变状态:不靠隐式 DI 藏环,把一节点 actor 化、改发消息。
480
+ - 别过度设计:vendor 原语优先;没有第二实现就不抽象;以防万一的开关不加。
481
+
482
+ **file-in / file-out**:重要输入/结论落文件,不只留对话;按职责分类(架构规则 → 本文件/owner doc;研究 → 分析;缺陷诊断 → bug;手测发现 → testing)。窗口是临时上下文,文件才是仓库记忆。
483
+
484
+ ---
485
+
486
+ ## 12. 测试:保护吸引子、不固化实现
487
+
488
+ DEPA 的结构让测试天然好写;但测试本身也会**沿实现时序腐蚀**,反过来阻碍结构演进。吸引子对测试的约束:
489
+
490
+ - **测行为/契约,不测实现时序**:测试钉在"对外可观测行为/契约"上,不钉在旧实现的内部时序。一次去掉局部状态镜像就崩一片测试,往往不是一片 bug,而是**测试早已与旧实现耦合**——这是测试漂移,要修测试结构,不是回退重构。
491
+
492
+ ```text
493
+ ❌ 测试钉在实现时序上(脆性,重构必崩)
494
+ expect(spy).toHaveBeenNthCalledWith(3, ...) // 第几次调用、内部顺序
495
+ ✅ 测试钉在对外行为/契约上
496
+ expect(result).toEqual(expectedOutput) // 同输入得同输出,内部怎么变都行
497
+ ```
498
+
499
+ - **core 即 `fn(mockRuntime, input, config)`**:I1 让核心逻辑可用 mock runtime 单测,不连真实库/网络;副作用经契约 mock,断言"调了哪个契约"。这是 DEPA 可测性的根。
500
+
501
+ ```text
502
+ ✅ 用 mock runtime 单测 core,断言副作用契约被调用
503
+ runtime = { db:{ users:{ create: mock() } }, logger:{ info: mock() } }
504
+ out = await createUser(runtime, { data }, null)
505
+ assert runtime.db.users.create.calledWith(data)
506
+ ```
507
+
508
+ - **contract / impl 分离 → 对契约测**:core 只依赖契约,测试注入 mock 契约;impl 单独测;不让测试里出现真实数据库/HTTP。
509
+ - **把不变量当成测试性质**:单一写入者、衍生不反写、状态可从事件重放重建、依赖单向无环——都是可断言的结构性质,值得有针对性的守护。
510
+
511
+ ```text
512
+ ✅ 结构性质测试
513
+ assert fold(reducer, replay(events)) == currentState // 状态可重建
514
+ assert no_write_path(projection -> events) // 衍生不反写
515
+ assert no_import(capsuleA -> capsuleB.internals) // 依赖不触 internals
516
+ ```
517
+
518
+ - **adapter / runtime 构造要覆盖**:outer→inner 字段映射、config 传递、output 透传、runtime 构造(尤其 registry 加载与下传)都要测——封装流程最易错处。
519
+ - **删旧前先用回归守住旧行为**:替换旧 OO/旧 wrapper 时,先用回归测试钉住旧行为,再删。
520
+ - **流程慢就建 test harness**:完整跑一遍验证很慢时,建一套专属测试工具/夹具支持未来同类问题。可测试性本身是代码质量指标——DOP + 四层分离写出来的代码天然好测。
521
+ - **测试数据与测试代码分离**:当测试数据多、体积大时,把测试数据分离到一个**专门目录**,与测试逻辑分开——便于复用、维护与版本管理,不要把大块 fixture 内联进测试代码。具体放哪按项目约定(如 `tests/resources/` 之类),规则是"分离",位置不强制。
522
+ - **三级验证阶梯**:验"做了没"逐级加深——**存在性**(目标产物/函数/测试确实存在、不是空壳)→ **实质性**(它真做了该做的事、断言真行为而非占位)→ **连通性**(与上下游真接通、端到端跑得通,不是孤立通过)。只过存在性就报完成,是最常见的假完成。
523
+ - **生成 ≠ 验收**:AI 同一上下文会同时产出代码、类型、测试、完成总结——若理解有偏,全部"证据"会一致偏向同一方向(自验证陷阱)。**完成判定必须回到 live 仓库**,由 fresh session / 独立审计重判,而非实现者自报 `- [x]`。
524
+ - **测试是度量,不是真源**:`test/lint/typecheck/build` 把高频显式偏离下推到机器层,是**度量**;它们护当前行为,不定义结构。结构方向以本文件为准。
525
+
526
+ ---
527
+
528
+ ## 13. 常见误读(保留"为什么不那样")
529
+
530
+ 吸引子的一部分记忆是"哪条路被证伪了"。下面是 DEPA 实践中反复出现、需要主动纠正的误读:
531
+
532
+ - **把 runtime 归给 Effect 一维**:runtime 是 D(主)+ E(少)+ A(复杂时)的共同展开,不专属 Effect。它首先是数据载体。
533
+ - **把标准组件流程画成 D/P 混格**:`Outer Input → Transform → Core → Outer Output` 把数据名词与逻辑动词当同类节点串一行,正是它要反对的三段式心智——必须数据血缘(D)与处理器(P)分列。
534
+ - **把 runtime 当成必须长成某固定层数**:不是;丰俭由人,判不变量不判形状。
535
+ - **把 actor 当并发工具**:actor 首先为打断环、显式化共享状态所有权而用,并发是顺带。
536
+ - **为"标准/可扩展"而过度设计**:标准封装、分发引擎、adapter 都只在有实际转换/动态路由需求时用;为固定逻辑套壳本身是违反。
537
+ - **把吸引子当护栏**:护栏答"什么不能做、越界即错";吸引子答"长期该收敛到哪、持续偏离才腐蚀"。把吸引子降格成更严的护栏,就丢了它处理"扰动下稳定性"的核心能力。
538
+ - **把文档完成当代码正确**:owner doc 写了正确行为,也不替代回到 live 仓库验证;真正闭合要回到代码/测试/审计证据。
539
+
540
+ ---
541
+
542
+ ## 14. 吸引子与 harness
543
+
544
+ 吸引子定方向,harness 把轨迹持续拉回方向。三类 harness 与本文件的关系:
545
+
546
+ - **本文件(owner doc)** = 吸引子的载体:结构方程、合法方向、排除集。
547
+ - **编码期纠偏清单**(§11 的触发表/反射)= 写前自检、命中排除集即改的执行 harness。
548
+ - **扫描分析**(§10 的收敛脉络)= 从现状到改造建议的分析 harness,产物落结构化文档。
549
+ - **测试 / 类型 / lint / 审计** = 度量与独立验收:生成与验收分离,完成回 live 仓库重判。
550
+
551
+ 真正的回路不是"定义一次吸引子、永远执行 harness",而是:**定义吸引子 → 扩张 → 纠偏 → 修订吸引子 → 再扩张**。当实践证明某个结构切分更稳(如把一个臃肿层拆成几层并列 capsule、把一个本质环 actor 化),吸引子本身被修订得更精确,然后在新基线上继续扩张。
552
+
553
+ > 新吸引子的定义(新的概念切分、边界重定义)通常需要人先提出——AI 擅长在既定吸引子周围快速扩张与收敛,但不会在高速迭代里自行演化出新吸引子。把这份架构判断**外化成可版本化、可审计、可继承的文件**,正是本文件存在的意义。
554
+
555
+ ---
556
+
557
+ ## 附录:术语对照
558
+
559
+ | 术语 | 含义(一句话) |
560
+ |------|----------------|
561
+ | **DEPA** | Data / Effect / Processor / Actor 四维 + 标准化组件协议 + 事实源边界 的架构思想 |
562
+ | **吸引子 attractor** | 系统长期被反复拉回的稳定结构;用少数不变量隐式定义,非清单非边界 |
563
+ | **harness** | 把轨迹持续拉回吸引子的机制:纠偏清单、扫描分析、测试/类型/审计 |
564
+ | **runtime** | 长生命周期依赖与状态的数据载体(D 主 + E 少 + A 时含),不写业务逻辑 |
565
+ | **fn(runtime,input,config)** | 核心逻辑的纯函数形态:依赖显式、副作用分离 |
566
+ | **数据血缘(D) / 处理器(P)** | 封装流程里"数据名词链"与"逻辑纯函数"两块,分列、绝不同格 |
567
+ | **事实等级 / 唯一写入者** | 数据节点在 7 级阶梯的位置 / 它唯一的权威写入者 |
568
+ | **衍生不反写** | 投影/缓存/快照只读,要改发新事件回上游,不直接改投影 |
569
+ | **capsule** | 单入口、internals 隐藏、对外只暴露稳定契约的模块单元 |
570
+ | **command / message** | 同步命令(同栈)/ 异步消息(经 mailbox) |
571
+ | **actor** | 单一所有权的解环/并发单元;环或共享可变状态时把一节点 actor 化 |
572
+ | **排除集** | 已不属于合法状态空间的老结构;发现即漂移,应收敛掉 |