@bolloon/bolloon-agent 0.5.5 → 0.6.0

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 (109) hide show
  1. package/dist/agents/parse-tool-call.js +6 -1
  2. package/dist/agents/pi-sdk-session-factory.js +36 -3
  3. package/dist/agents/pi-sdk.js +349 -199
  4. package/dist/agents/run-context.js +20 -0
  5. package/dist/agents/runner-resolver.js +2 -1
  6. package/dist/electron-build/agents/parse-tool-call.js +6 -1
  7. package/dist/electron-build/agents/parse-tool-call.js.map +1 -1
  8. package/dist/electron-build/agents/pi-sdk-session-factory.js +36 -3
  9. package/dist/electron-build/agents/pi-sdk-session-factory.js.map +1 -1
  10. package/dist/electron-build/agents/pi-sdk-types.js.map +1 -1
  11. package/dist/electron-build/agents/pi-sdk.js +349 -199
  12. package/dist/electron-build/agents/pi-sdk.js.map +1 -1
  13. package/dist/electron-build/agents/run-context.js +24 -0
  14. package/dist/electron-build/agents/run-context.js.map +1 -0
  15. package/dist/electron-build/agents/runner-resolver.js +2 -1
  16. package/dist/electron-build/agents/runner-resolver.js.map +1 -1
  17. package/dist/electron-build/kernel/channel-actor.js +314 -0
  18. package/dist/electron-build/kernel/channel-actor.js.map +1 -0
  19. package/dist/index.js +24 -19
  20. package/dist/kernel/channel-actor.js +297 -0
  21. package/dist/kernel/control.js +95 -0
  22. package/dist/kernel/gate-scan.js +1036 -0
  23. package/dist/kernel/model-runtime.js +472 -0
  24. package/dist/kernel/plan-channel-actor.js +298 -0
  25. package/dist/kernel/plan-constraint.js +165 -0
  26. package/dist/kernel/plan-deletion.js +32 -0
  27. package/dist/kernel/plan-modelruntime.js +60 -0
  28. package/dist/kernel/plan-runcontext.js +163 -0
  29. package/dist/kernel/plan.js +153 -0
  30. package/dist/kernel/roster.js +242 -0
  31. package/dist/web/bolloon-web.json +3 -3
  32. package/dist/web/client.js +3 -2
  33. package/dist/web/routes-tasks.js +5 -1
  34. package/dist/web/server.js +58 -18
  35. package/dist/web/sw.js +1 -1
  36. package/dist/web/ui/message-renderer.js +473 -29
  37. package/dist/web/ui/step-timeline.js +13 -12
  38. package/package.json +1 -1
  39. package/scripts/build-web.ts +74 -1
  40. package/dist/constraint-runtime/_archive_helper.d.ts +0 -1
  41. package/dist/constraint-runtime/_archive_helper.js +0 -9
  42. package/dist/constraint-runtime/assistant/index.d.ts +0 -11
  43. package/dist/constraint-runtime/assistant/index.js +0 -12
  44. package/dist/constraint-runtime/bootstrap/index.d.ts +0 -11
  45. package/dist/constraint-runtime/bootstrap/index.js +0 -12
  46. package/dist/constraint-runtime/bridge/index.d.ts +0 -11
  47. package/dist/constraint-runtime/bridge/index.js +0 -12
  48. package/dist/constraint-runtime/buddy/index.d.ts +0 -11
  49. package/dist/constraint-runtime/buddy/index.js +0 -12
  50. package/dist/constraint-runtime/cli/index.d.ts +0 -11
  51. package/dist/constraint-runtime/cli/index.js +0 -12
  52. package/dist/constraint-runtime/components/index.d.ts +0 -11
  53. package/dist/constraint-runtime/components/index.js +0 -12
  54. package/dist/constraint-runtime/constants/index.d.ts +0 -11
  55. package/dist/constraint-runtime/constants/index.js +0 -12
  56. package/dist/constraint-runtime/coordinator/index.d.ts +0 -11
  57. package/dist/constraint-runtime/coordinator/index.js +0 -12
  58. package/dist/constraint-runtime/cost_hook.d.ts +0 -2
  59. package/dist/constraint-runtime/cost_hook.js +0 -4
  60. package/dist/constraint-runtime/entrypoints/index.d.ts +0 -11
  61. package/dist/constraint-runtime/entrypoints/index.js +0 -12
  62. package/dist/constraint-runtime/execution_registry.d.ts +0 -20
  63. package/dist/constraint-runtime/execution_registry.js +0 -44
  64. package/dist/constraint-runtime/hooks/index.d.ts +0 -11
  65. package/dist/constraint-runtime/hooks/index.js +0 -12
  66. package/dist/constraint-runtime/ink.d.ts +0 -1
  67. package/dist/constraint-runtime/ink.js +0 -4
  68. package/dist/constraint-runtime/keybindings/index.d.ts +0 -11
  69. package/dist/constraint-runtime/keybindings/index.js +0 -12
  70. package/dist/constraint-runtime/memdir/index.d.ts +0 -11
  71. package/dist/constraint-runtime/memdir/index.js +0 -12
  72. package/dist/constraint-runtime/migrations/index.d.ts +0 -11
  73. package/dist/constraint-runtime/migrations/index.js +0 -12
  74. package/dist/constraint-runtime/moreright/index.d.ts +0 -11
  75. package/dist/constraint-runtime/moreright/index.js +0 -12
  76. package/dist/constraint-runtime/native_ts/index.d.ts +0 -11
  77. package/dist/constraint-runtime/native_ts/index.js +0 -12
  78. package/dist/constraint-runtime/output_styles/index.d.ts +0 -11
  79. package/dist/constraint-runtime/output_styles/index.js +0 -12
  80. package/dist/constraint-runtime/plugins/index.d.ts +0 -11
  81. package/dist/constraint-runtime/plugins/index.js +0 -12
  82. package/dist/constraint-runtime/port_manifest.d.ts +0 -7
  83. package/dist/constraint-runtime/port_manifest.js +0 -11
  84. package/dist/constraint-runtime/query.d.ts +0 -6
  85. package/dist/constraint-runtime/query.js +0 -1
  86. package/dist/constraint-runtime/remote/index.d.ts +0 -11
  87. package/dist/constraint-runtime/remote/index.js +0 -12
  88. package/dist/constraint-runtime/schemas/index.d.ts +0 -11
  89. package/dist/constraint-runtime/schemas/index.js +0 -12
  90. package/dist/constraint-runtime/screens/index.d.ts +0 -11
  91. package/dist/constraint-runtime/screens/index.js +0 -12
  92. package/dist/constraint-runtime/server/index.d.ts +0 -11
  93. package/dist/constraint-runtime/server/index.js +0 -12
  94. package/dist/constraint-runtime/services/index.d.ts +0 -11
  95. package/dist/constraint-runtime/services/index.js +0 -12
  96. package/dist/constraint-runtime/state/index.d.ts +0 -11
  97. package/dist/constraint-runtime/state/index.js +0 -12
  98. package/dist/constraint-runtime/system_init.d.ts +0 -1
  99. package/dist/constraint-runtime/system_init.js +0 -20
  100. package/dist/constraint-runtime/types/index.d.ts +0 -11
  101. package/dist/constraint-runtime/types/index.js +0 -12
  102. package/dist/constraint-runtime/upstream_proxy/index.d.ts +0 -11
  103. package/dist/constraint-runtime/upstream_proxy/index.js +0 -12
  104. package/dist/constraint-runtime/utils/index.d.ts +0 -11
  105. package/dist/constraint-runtime/utils/index.js +0 -12
  106. package/dist/constraint-runtime/vim/index.d.ts +0 -11
  107. package/dist/constraint-runtime/vim/index.js +0 -12
  108. package/dist/constraint-runtime/voice/index.d.ts +0 -11
  109. package/dist/constraint-runtime/voice/index.js +0 -12
@@ -0,0 +1,298 @@
1
+ /**
2
+ * **K5 台账: Channel Actor** (leo 2026-10-02 定口径)
3
+ *
4
+ * 从 K2 移交过来的背景: `messageHistory` / `currentChannelId` / `currentAgentId` / `currentGoalId`
5
+ * 四个字段**不是 Run 状态, 是会话状态** —— 它们不属于 RunContext, 该由 Channel Actor 统一承载。
6
+ * K2 已把它们标 `scope: 'session'` 并逐字保留在 Pi 实例上 (零搬迁), 这里记的是**最终归属与迁移步骤**。
7
+ *
8
+ * 判据: `src/test/kernel-channel-actor.test.ts` —— 台账必须与**盘上事实同步**:
9
+ * 标了"容器未建"就必须真的不存在 `src/kernel/channel-actor.ts`; 进度只许增; 未建/未迁的不许标成已完成。
10
+ */
11
+ /**
12
+ * 进度历史 (台账只许前进, 每次前进都要留下日期与"这一步交付了什么"):
13
+ * · 2026-10-02 not-started → **container-built**: `src/kernel/channel-actor.ts` 落地
14
+ * (ActorState 9 项 · SerialMailbox 串行队列 · ChannelActor.submit/abort/beginCancellation);
15
+ * 串行语义由 `kernel-channel-actor.test.ts` **真跑**验证; **尚未接任何入口** ⇒ 行为零改变。
16
+ * · 2026-10-02 container-built → **registry-built**: 注册表 `getOrCreateActor(peekActor/actorCount/resetActors)`
17
+ * 落地, 并由 **session factory** 在会话创建时按 channel 绑定 (`attachActor`) ⇒ 一个 channel 一个 actor 成立;
18
+ * `fieldsMigrated` 仍 0/4 · `entriesWired` 仍 0/4 (只做归属, 没有把执行投递进 mailbox, 状态仍在 Pi 实例上)。
19
+ * · 2026-10-02 **第 4 步第一版被全量回归否掉, 已回退** (证据留在 §28):
20
+ * 曾把 history 本体搬进 `actor.state.messageHistory` (Pi 侧改成访问器 + `attachActor` 收养)。
21
+ * 全量 **4742 测试 ⇒ 6 红**, 两类根因:
22
+ * ① **会话隔离被打破** (5 红): actor 的注册键是 `peerId` 的 `:` 前段 (或 `default`), 而
23
+ * **会话身份 (SessionStore key) 在 hydrate 时才出现** ⇒ 两个独立 session 共用同一个 actor,
24
+ * 新 session 一构造就看到别人的 history (测试实测 `expected 2 to be 0`)。
25
+ * ② **K2 门拦下** (1 红): 「session 级字段必须**仍是实例字段**」—— 第 4 步落地前不许留半搬状态。
26
+ * ⇒ **结论 (写进 K5 约束)**: history 归属**不能按 channel 前缀**, 必须按**会话身份**。
27
+ * · 2026-10-02 **第二版 (按约束重做, 成功)**: 注册键改成**会话身份** (`loadSessionKey` 优先, 否则整条 `peerId`),
28
+ * **不做前缀归并, 也没有 default 兜底桶** (没有身份 ⇒ 不归属: 宁可不共享, 不许串台);
29
+ * `messageHistory` 本体搬进 `actor.state.messageHistory` (Pi 侧访问器 + `attachActor` 收养当地历史)。
30
+ * 同时把 K2 门那条「session 级字段必须仍是实例字段」改成**读 K5 台账**的交接契约 (声明了才放行)。
31
+ * `fieldsMigrated` 0 → **1/4** (messageHistory); `entriesWired` 仍 0/4。
32
+ * · 2026-10-02 同一格继续: **history 的 hydrate / persist 实现体搬进 Actor**
33
+ * (`hydrateHistory` = load→filter→截断→替换, `historySnapshot` = persist 的取数拍, `appendMessage` 备用),
34
+ * 业务侧只交**纯回调** (内核不 import 业务模块) —— 三个操作**走邮箱** ⇒ 同 Channel 内与 append 串行,
35
+ * 不再有"读-改-写三拍被并发踩掉"和"边写边读抓到半截状态"。
36
+ * `historyOpsMigrated 2/4` (hydrate · persist)。
37
+ * · 2026-10-02 同格继续: **append 收敛** —— `pi-sdk.ts` 里 history 的写入面 (实测 push 31 · pop 1 · 整体赋值 3)
38
+ * 全部收敛到唯一漏斗 `pushHistory` / `popHistory` / `replaceHistory` ⇒ 每个直写模式只剩漏斗自身 1 处,
39
+ * 判据 `scanHistoryWriteSites` 断言这一点。**漏斗有意做成同步**: 调用点写完立刻要读 (length/索引/slice),
40
+ * 改成 await 会改变同拍可见性 —— 它交付的是**归属与可数性**, 并发安全由入口投递负责 (K5 第 5 步)。
41
+ * `historyOpsMigrated 3/4` (hydrate · append · persist)。
42
+ * · 2026-10-02 同格收官: **compact 落地拍** —— 压缩是 async, 从取快照到落地之间有 await 窗口,
43
+ * 期间 append 的消息原先会被整块替换**丢掉** (lost update) ⇒ 新增 `actor.rebaseHistory(compacted, snapshotLen)`
44
+ * (走邮箱 + 把快照之后的尾部原样接回); 同步压缩路径经核实是"同一拍相邻两行"(无窗口), 只留注释警戒。
45
+ * `historyOpsMigrated **4/4**` (hydrate · append · compact · persist)。
46
+ * · 2026-10-02 **步骤③ (三个会话绑定迁入 Actor)**: `currentChannelId` / `currentAgentId` / `currentGoalId`
47
+ * 的本体住进 `actor.state.channelId` / `.agentId` / `.goalBinding` (Pi 侧改成访问器 + `attachActor` 收养
48
+ * 构造期已设的值)。**这三个字段的访问数不变** (24 / 21 / 22) —— 迁的是**所有权**而非删访问,
49
+ * 所以本次**不动** K2 台账的冻结值 (判据的"少一处才红"在这里不适用, 因为一处也没少)。
50
+ * `fieldsMigrated **4/4**`。
51
+ * · 2026-10-02 **步骤④ 起手 (入口投递)**: `deliverThroughActor(holder, run)` 落进内核 —— 有 actor 就投进
52
+ * 它的 mailbox (同一会话身份的输入**排队**), 无 actor 直接跑 (行为不变)。**web 用户路径已接 3 处**
53
+ * (用户消息 / 第二条路径 / 重新生成), `web/server.ts` 里共 8 处入口执行点 ⇒ `entrySites { total: 8, wired: 3 }`,
54
+ * 两个数字都由判据 `scanEntryDelivery` **从盘上重算**, 自报无效。
55
+ * 四个**粗粒度**入口 (web / CLI / P2P / Supervisor) 的 `entriesWired` 仍 **0/4** —— 一条入口要全部执行点接完才算。
56
+ * · 2026-10-02 **步骤④ 完成**: web (server.ts 11/11 + routes-tasks 1/1) · CLI (index.ts) · P2P 入站 · Supervisor/子Agent
57
+ * (runner-resolver.ts 1/1) ⇒ `entriesWired **4/4**`。
58
+ * **关键发现 (口径漏了一整类入口)**: P2P 入站调的是 `a.summarizeDocument(...)` / `a.improveDocument(...)` ——
59
+ * 不叫 `prompt`, 只数 prompt/promptStream 会让这条入口**永远数不到** (实测 index.ts 漏 4 处)。
60
+ * ⇒ 口径的方法名单 `AGENT_ENTRY_METHODS` 也做成台账数据 (冻结), 并配判别力用例。
61
+ */
62
+ /** K5 第 4 步: 四个 history 操作 (唯一来源; 台账 `historyOpsNames` 必须 ⊆ 这里, 且数量与进度位一致) */
63
+ export const HISTORY_OPS = ['hydrate', 'append', 'compact', 'persist'];
64
+ /** Actor 状态容器必须承载的 9 项 (leo 定的清单) */
65
+ export const ACTOR_STATE_ITEMS = [
66
+ { name: 'channelId', why: "会话绑定的通道 —— 迁移前是 Pi 实例字段 (match 计数 24)", owner: 'actor' },
67
+ { name: 'agentId', why: "会话身份 —— 迁移前 21 处", owner: 'actor' },
68
+ { name: 'goalBinding', why: "会话的 Goal 默认绑定 —— **保留为 Actor 级默认**, 但每次执行开始必须把最终绑定写进 RunContext/Run 记录", owner: 'actor' },
69
+ { name: 'messageHistory', why: "**Channel 的连续记忆** (不是 Run 历史): 同 Channel 串行访问, 跨 Channel 必须隔离", owner: 'actor' },
70
+ { name: 'mailbox', why: "入站消息队列 —— 同 Channel 内只能排队, 不能并发改 history", owner: 'actor' },
71
+ { name: 'activeRun', why: "当前活跃 Run (取代 Pi 上的 currentRunId 播种)", owner: 'actor' },
72
+ { name: 'cancellation', why: "取消位 (取代 Pi 上的 currentSignal)", owner: 'actor' },
73
+ { name: 'outboundStream', why: "出站流 (取代 Pi 上的 currentOnStream)", owner: 'actor' },
74
+ { name: 'serialLock', why: "**同 Channel 串行执行锁** (1 个 channel 同时只有 1 个 Run 在改状态)", owner: 'actor' },
75
+ ];
76
+ /** K5 验收标准 (leo 2026-10-02; 其中「并发 Run 的 history 不互相污染」是从 K2 移过来的) */
77
+ export const K5_ACCEPTANCE = [
78
+ '① 同 Channel 消息串行 (输入只能排队, 不能并发改 history)',
79
+ '② 不同 Channel history 完全隔离 (不交叉)',
80
+ '③ 同一 Channel 的多个 Run 不互相污染 (Actor 串行调度 + Run 边界隔离)',
81
+ '④ 页面 / CLI / P2P / Supervisor 都进入同一 Actor mailbox',
82
+ '⑤ Actor 崩溃后可由 Supervisor 恢复',
83
+ '⑥ messageHistory 不再由 Pi 直接拥有',
84
+ ];
85
+ /** 8 步迁移步骤 (leo 定的顺序) —— 每步都要带真跑 */
86
+ export const K5_STEPS = [
87
+ '① 创建 Actor 状态容器 (9 项)',
88
+ '② messageHistory 的 hydrate / compact / append / persist 迁入 Actor',
89
+ '③ currentChannelId / currentAgentId / currentGoalId 迁入 Actor',
90
+ '④ 所有入口改为投递消息 (submit → mailbox)',
91
+ '⑤ 每个 Channel 内加串行执行锁',
92
+ '⑥ currentRunId 改成 Actor 的 activeRun / ExecutionFrame',
93
+ '⑦ Pi 只接收一次性的 ExecutionRequest',
94
+ '⑧ 删除 Pi 中对应字段',
95
+ ];
96
+ /** 删除旧字段的 7 条前置条件 (全满足才许删 —— 对应 §7.3 删除条件的 K5 细化) */
97
+ /**
98
+ * K5 的 7 条删除前置。每条**必须点名"谁证明它"** (`backedBy`) —— 说"已验证"却没点名, 或点了一个盘上不存在的文件/判据,
99
+ * 都由 `scanPreconditionBacking` 判红 (不谎称可验证性: 判据只核"背书存在", 不代替真跑)。
100
+ */
101
+ export const K5_DELETION_PRECONDITIONS = [
102
+ {
103
+ text: 'PiAgentSession 不再拥有 session 状态',
104
+ backedBy: ['src/test/kernel-channel-actor.test.ts', 'K5_FIELD_DELETION'],
105
+ },
106
+ {
107
+ text: '所有入口都经过 Channel Actor',
108
+ backedBy: ['src/test/kernel-channel-actor.test.ts'], // scanEntryDelivery: wiredTotal === total
109
+ },
110
+ {
111
+ text: '同 Channel 串行、跨 Channel 并发**真跑通过**',
112
+ backedBy: ['src/test/kernel-channel-actor.test.ts'], // 串行语义 + ALS 防重入自锁
113
+ },
114
+ {
115
+ text: '重启后 history / Goal / Run 仍能正确恢复',
116
+ backedBy: ['src/test/session-resume-e2e.test.ts', 'src/test/persistence-e2e-flow.test.ts'],
117
+ },
118
+ {
119
+ text: 'currentRunId 不再由 Pi 负责播种',
120
+ backedBy: ['scanRunIdSeed'], // CURRENT_RUN_ID_SEED_READS/_SEED_SITES
121
+ },
122
+ {
123
+ text: 'Pi 的字段访问只剩推理所需的临时变量',
124
+ backedBy: ['K5_ACCESSOR_SURFACE'],
125
+ },
126
+ {
127
+ text: '旧字段零引用门禁通过',
128
+ backedBy: ['K5_FIELD_DELETION'], // scanStagingFieldDeletion 双向
129
+ },
130
+ ];
131
+ /**
132
+ * **K5 步骤⑧ 的棘轮**: "本体已进 actor"之后, pi-sdk 里对这批**访问器**的引用数只许减、不许再增。
133
+ * 删访问器本身要改 ~129 处 + 10 个文件 (跨 web/CLI/agents), 属大范围改名 ⇒ 立棘轮而不是硬改。
134
+ * 计数变化 ⇒ 台账必须在**同一次提交**里跟上 (台账与盘上事实必须同步)。
135
+ */
136
+ export const K5_ACCESSOR_SURFACE = {
137
+ accessorFields: ['messageHistory', 'currentChannelId', 'currentAgentId', 'currentGoalId', 'currentRunId'],
138
+ frozenInPiSdk: { messageHistory: 0, currentChannelId: 0, currentAgentId: 0, currentGoalId: 0, currentRunId: 0 }, // 批次5: 5 个访问器全部归零
139
+ where: 'src/agents/pi-sdk.ts',
140
+ why: '字段本体已删 (K5_FIELD_DELETION); 这些访问器只剩"读门面"作用 ⇒ 只许减',
141
+ };
142
+ /** 从 K2 移交的 4 个 session 字段 (现仍是 Pi 实例字段, match 口径冻结值) */
143
+ export const K5_INHERITED_FIELDS = [
144
+ { name: 'messageHistory', into: 'actor.messageHistory', accesses: 0 }, // 步骤⑧ 批次 1: pi-sdk 侧 0 引用
145
+ // K5 步骤⑦ 起 +1: `applyExecutionRequest` 把请求里的绑定写进这三个字段 (各一处写)
146
+ { name: 'currentChannelId', into: 'actor.channelId', accesses: 0 }, // 步骤⑧ 批次4: pi-sdk 侧 0 引用
147
+ { name: 'currentAgentId', into: 'actor.agentId', accesses: 0 }, // 步骤⑧ 批次2: pi-sdk 侧 0 引用
148
+ { name: 'currentGoalId', into: 'actor.goalBinding', accesses: 0 }, // 步骤⑧ 批次3: pi-sdk 侧 0 引用
149
+ ];
150
+ /**
151
+ * 从 K2 移交的四个 session 字段的**当前**访问数 (match 口径, 与 K2 台账逐字相等 —— 跨台账判据强制)。
152
+ * ⚠️ `messageHistory` 由 56 降到 **22**: K5 第 4 步把 35 处写入 (push 31 · pop 1 · 整体赋值 3)
153
+ * 收敛进唯一漏斗 (`pushHistory`/`popHistory`/`replaceHistory`) 后这些点不再直接访问实例字段;
154
+ * 随后 compact 落地又**加了 1 处** (`snapshotLen = this.messageHistory.length`, 压缩的取快照拍)。
155
+ * 这不是"泄漏消失", 是**迁移动作的可见痕迹** —— 数字对不上就必须回去核 (门已两次拦下这类不同步)。
156
+ */
157
+ /**
158
+ * **启动一次执行的 AgentSession 方法名单** (判据口径的数据来源, 冻结)。
159
+ * 为什么必须列全: 只数 `prompt/promptStream` 会让"走文档摘要/改写进来的入口"(P2P 入站)
160
+ * **永远数不到** —— 实测 `index.ts` 因此漏了 4 处 (`summarizeDocument` ×2 · `improveDocument` ×2)。
161
+ * 故意不计的: `readDocument` (纯 IO) · `suggestRename` (单次小调用, 不写会话历史) ·
162
+ * `runWorkflow` (内部会再调 prompt ⇒ 计入会双算)。
163
+ */
164
+ export const AGENT_ENTRY_METHODS = [
165
+ 'prompt', 'promptStream', 'promptWithPivotLoop', 'summarizeDocument', 'improveDocument',
166
+ // K5 步骤⑦ 新增的唯一入口: 请求式投递 (`runExecution`) 也是**启动一次执行** ——
167
+ // 不列进来会让"改写成请求式"的站点从执行点计数里**消失** (实测: 一改成请求式, 该文件 total 就从 11 掉到 10)。
168
+ 'runExecution',
169
+ ];
170
+ /**
171
+ * **K5 步骤⑤ channel 级串行锁的状态** (数据; 判据要求 `enabled` 与盘上调用点数一致):
172
+ * · 证据 (为什么默认不启用): web 的 channel 只有一个 `currentSessionId` ⇒ 用户消息都投到**同一个会话身份**
173
+ * ⇒ 身份级串行 (mailbox) **已经把这个 channel 的活跃会话串起来了** (验收①在活跃会话上已成立);
174
+ * · 什么时候才需要它: 会话切换后旧会话仍在内存 ⇒ 两个身份可能并行 (**各写自己的 history, 无污染**);
175
+ * 若要"跨会话切换也串行", 才需要 channel 级锁;
176
+ * · 代价: 同 channel 的**多个 agent** (P2P 多智能体) 也会被串起来 ⇒ 吞吐下降。
177
+ * ⇒ 是否全局启用 = **意图层决定** (leo); 能力 (`deliverThroughActor(..., {serializeByChannel:true})`) 已备好。
178
+ */
179
+ export const K5_CHANNEL_LOCK = {
180
+ available: true,
181
+ enabled: false,
182
+ /** 盘上真正传了 `serializeByChannel: true` 的调用点数量 (判据从盘上重算, 不许自报) */
183
+ callSites: 0,
184
+ /** 证据出处 (一 channel 一活跃会话身份) */
185
+ evidence: 'web/server.ts:1566-1567 — channel.currentSessionId ⇒ sessionKey = <channelId>:<currentSessionId>',
186
+ };
187
+ /**
188
+ * **K5 步骤⑥**: Run 身份的归属 (run-boundary 作用域, 从 K2 的"唯一播种读取"收口过来)。
189
+ * `currentRunId` 的本体从 Pi 实例字段搬进 `actor.state.activeRun` —— 判据 `scanRunBoundaryResidence`
190
+ * 会核对盘上源码里**是否还有** `private currentRunId` 声明 (双向: 声明了却没标未迁 · 没声明却标未迁, 都红)。
191
+ */
192
+ export const K5_RUN_BOUNDARY = {
193
+ field: 'currentRunId',
194
+ into: 'actor.activeRun',
195
+ migrated: true,
196
+ /** K2 留下的唯一播种读取 (不因本步而增加; 由 K2 的门强制) */
197
+ seedReads: 1,
198
+ };
199
+ /**
200
+ /**
201
+ * **K5 步骤⑧ — 实例侧"绑定前暂存"字段已删除** (data; 判据核对盘上是否真的没有它们)。
202
+ * Pi 出生就带一个**私有 actor** (未注册 ⇒ 谁也拿不到), 工厂知道会话身份时再升级成身份键 actor 并**收养**状态
203
+ * ⇒ 实例侧不再需要暂存字段。删掉它们同时消灭了两类隐患: "两份真相" 与 "兜底分支写错成自递归"。
204
+ */
205
+ export const K5_FIELD_DELETION = {
206
+ /** 本源里曾经有过的暂存字段全清单 (双向判据的另一半: 少登记一个 ⇒ 红) */
207
+ sourceFields: ['_history', '_channelId', '_agentId', '_goalId', '_runId'],
208
+ deletedStagingFields: ['_history', '_channelId', '_agentId', '_goalId', '_runId'],
209
+ why: 'actor 从出生就在 (私有无身份 / 身份键有身份), 暂存那份多余; 删掉即"删字段"这一步的可见痕迹',
210
+ };
211
+ /** K5 步骤⑦: 一次性 `ExecutionRequest` 的收敛进度。
212
+ * Pi 侧已加唯一入口 (`applyExecutionRequest` 落绑定 · `runExecution` 派发);
213
+ * 入口面 **converted = 1** (web 用户消息路径)。
214
+ * `remaining` 是**派生值** (已投递点数 − converted) —— 位置式形态太多, 行级正则数不准,
215
+ * 与其编一个假精确的门, 不如把"请求式"这半钉死, 剩下用算术表示。
216
+ */
217
+ export const K5_EXECUTION_REQUEST = {
218
+ methodAdded: true,
219
+ converted: 1,
220
+ wiredTotal: 24,
221
+ remaining: 23,
222
+ };
223
+ /** 入口 → 文件分组 (判据做**双向**校验: 说完成 ⇒ 其文件必须全接完; 说没完成 ⇒ 必须真有文件没接完) */
224
+ export const K5_ENTRY_GROUPS = [
225
+ { entry: 'web', files: ['web/server.ts', 'web/routes-tasks.ts'], wired: true },
226
+ { entry: 'CLI', files: ['index.ts', 'cli/interface.ts'], wired: true },
227
+ { entry: 'P2P 入站', files: ['index.ts'], wired: true },
228
+ { entry: 'Supervisor/子 Agent', files: ['agents/runner-resolver.ts'], wired: true },
229
+ ];
230
+ /** 进度位 —— 门强制与盘上事实同步 (进度只许增; 未建的不许标已建) */
231
+ /**
232
+ * **K5 步骤⑧ 的终态声明** —— "删字段"这一步做完了。
233
+ * 声明**不是自报**: 判据 `scanStep8Completion` 会把三个条件**从盘上重算** (访问器引用数 / 暂存字段声明 / 入口投递),
234
+ * 任何一条不成立 ⇒ 红; 反过来"事实已完成而台账说没完成" ⇒ 也红 (双向, 台账必须与事实同步)。
235
+ */
236
+ export const K5_STEP8 = {
237
+ claimedComplete: true,
238
+ /** ① 5 个访问器在 pi-sdk 侧 0 引用 (由 scanAccessorSurface 从盘上重算) */
239
+ accessorRefsFrozenAtZero: K5_ACCESSOR_SURFACE.accessorFields.length,
240
+ /** ② 5 个"绑定前暂存"字段的声明不存在 (由 scanStagingFieldDeletion 的双向判据核) */
241
+ stagingFieldsDeleted: K5_FIELD_DELETION.deletedStagingFields.length,
242
+ /** ③ 入口投递 4/4 (由 scanEntryDelivery 从盘上重算) */
243
+ entriesWired: 4,
244
+ entriesTotal: 4,
245
+ why: '⑧ 完成的三个可数条件 —— 声明即需条件成立, 判据从盘上重算; 任一不成立或"事实已完成而台账说没完成"都判红',
246
+ };
247
+ export const K5_PROGRESS = {
248
+ stage: 'field-deletion-complete',
249
+ /** Actor 容器文件路径 (存在性由门真读盘核对) */
250
+ containerPath: 'kernel/channel-actor.ts',
251
+ fieldsMigrated: 4,
252
+ /** 已迁字段名单 —— 门强制 `length === fieldsMigrated` 且每个名字都在 K5_INHERITED_FIELDS 里 */
253
+ migratedFieldNames: ['messageHistory', 'currentChannelId', 'currentAgentId', 'currentGoalId'],
254
+ fieldsTotal: 4,
255
+ entriesWired: 4,
256
+ entriesTotal: 4,
257
+ /** 判据口径用的方法名单 (数据; 见 AGENT_ENTRY_METHODS 的说明) */
258
+ entryMethods: AGENT_ENTRY_METHODS,
259
+ /** 入口分组 (判据做双向校验: 说完成 ⇒ 文件必须全接完) */
260
+ entryGroups: K5_ENTRY_GROUPS,
261
+ /**
262
+ * K5 步骤④ 的细粒度进度: **全部入口面的执行点清单**。
263
+ * 两个数字都由判据 `scanEntryDelivery` 用同一口径**从盘上重算** (剥注释 / 排除 `this.prompt` / 非流式也算), 自报无效。
264
+ */
265
+ entrySites: [
266
+ // `excludeReceivers` 是**已核实的非执行点 receiver** (台账数据, 冻结; 改动会出现在 diff 里):
267
+ // `this` = CLI readline 提示 (`this.prompt('> ')`); `s` = index.ts 里的 UI 打印助手 (`s.prompt('📩 …')`)
268
+ { file: 'web/server.ts', total: 11, wired: 11, excludeReceivers: ['this'] }, // web 用户/中继/任务/心跳
269
+ { file: 'web/routes-tasks.ts', total: 1, wired: 1, excludeReceivers: ['this'] }, // web 任务路由
270
+ { file: 'index.ts', total: 11, wired: 11, excludeReceivers: ['this', 's'] }, // CLI 主入口 + P2P 入站 (含文档摘要/改写)
271
+ { file: 'cli/interface.ts', total: 0, wired: 0, excludeReceivers: ['this'] }, // readline ⇒ 无执行点
272
+ { file: 'agents/runner-resolver.ts', total: 1, wired: 1, excludeReceivers: ['this'] }, // 子 Agent / Supervisor 面
273
+ ],
274
+ /** K5 第 4 步里的 history **操作**搬迁 (4 个: hydrate/append/compact/persist) */
275
+ historyOpsMigrated: 4,
276
+ historyOpsTotal: 4,
277
+ /** 已搬操作名单 —— 门强制 `length === historyOpsMigrated` 且每个名字都在 HISTORY_OPS 里 */
278
+ historyOpsNames: ['hydrate', 'append', 'compact', 'persist'],
279
+ };
280
+ /** 四个入口 (leo 点名的) —— 全部要进同一 mailbox */
281
+ /**
282
+ * history 写入面的**迁移前实测值** (2026-10-02 grep 计数, 见 `scanHistoryWriteSites`):
283
+ * 判据是"每个模式最多剩 1 处直写 (漏斗自身)" —— 若哪天这两个数字对不上盘上事实, 说明有人绕过漏斗。
284
+ */
285
+ export const HISTORY_WRITE_SITES = { push: 31, pop: 1, assign: 3 };
286
+ /** history 写入的**唯一漏斗** (三个方法名; 判据要求它们真的存在) */
287
+ /**
288
+ * history 写入的三个唯一漏斗。**可见性也是台账的一部分** —— 判据的语义是"漏斗存在且形态与账一致",
289
+ * 所以把 `replaceHistory` 升成公开 (步骤⑧: 它是唯一的"种历史"入口, 上层/测试必须能调) 也必须现形于此。
290
+ */
291
+ export const HISTORY_WRITE_FUNNEL = [
292
+ { name: 'pushHistory', vis: 'private' },
293
+ { name: 'popHistory', vis: 'private' },
294
+ { name: 'replaceHistory', vis: 'public', why: '步骤⑧: 唯一的"种历史"入口 (直接赋数组会换掉数组身份 ⇒ 静默丢数据)' },
295
+ ];
296
+ export const K5_ENTRIES = ['web/server.ts', 'src/cli', 'P2P 入站', 'Supervisor'];
297
+ /** Goal 绑定必须是**显式操作**, 不许靠裸字段隐式生效 (leo 口径) */
298
+ export const K5_GOAL_BINDING_RULE = '运行中重新绑定 Goal 必须经过显式 Goal Binding 操作 (写 RunContext/Run 记录), 不许靠裸字段隐式生效';
@@ -0,0 +1,165 @@
1
+ /**
2
+ * **K1 —— constraint-runtime 三层分类名册 (primitives / runtime-adapters / domain-libraries)**
3
+ *
4
+ * 依据: leo 修订版 K1 —— ① 先统计真实 import ② 移除无调用模块 ③ 删假连接/placeholder
5
+ * ④ 领域模块改显式 Tool Provider ⑤ 最后删旧导出与兼容层。**本文件是第 ① 步的产物** (统计 + 分类), 不是删除本身。
6
+ *
7
+ * 判据: src/test/kernel-constraint.test.ts; 纯函数: src/kernel/gate-scan.ts。
8
+ *
9
+ * K1 真读出来的四条事实 (写在这里, 免得下一轮重新发现):
10
+ * · 源码 **94 文件 / 2492 行** (A 15 / B 24 / C 55);
11
+ * · **33 个 ≤20 行的空壳 index.ts** (共 460 行) —— 移植留下的骨架;
12
+ * · **dist/ 是构建产物, 且被 .gitignore 忽略** (从未进 git) — 但它**运行期必需**:
13
+ * 里面除了编译产物还有 `reference_data/*.json` **32 个快照** (tsc 不复制) ⇒ 见 CONSTRAINT_DIST_DATA_JSON;
14
+ * · constraint-runtime **自带的 4 个测试从来不跑** —— 仓里 vitest 配置把整个 constraint-runtime 目录排除在外 (见 vitest.config.ts 的 exclude)。
15
+ */
16
+ /** 三层分类 (A 原语 / B 领域工具 / C 不进 Kernel) + BUILD/META */
17
+ export const CONSTRAINT_RULES = [
18
+ { key: '__pkg_entry__', cls: 'A', why: "包入口公开面 —— 主仓经它拿到的是原语/会话/技能类型 (具体哪个符号见 A_ENTRY_USES)", phase: 'K1' },
19
+ { key: 'src/constraint/', cls: 'A', why: "约束原语: ToolPermissionContext + BudgetTracker (leo 点名的 A 类)", phase: 'K1' },
20
+ { key: 'src/skills/', cls: 'A', why: "SkillRegistry (技能元数据注册; 与执行器分离)", phase: 'K1' },
21
+ { key: 'src/agent/', cls: 'A', why: "AgentCoordinator: 子任务协调原语", phase: 'K1' },
22
+ { key: 'src/thinking/', cls: 'A', why: "DeepThinkingEngine: 推理原语 (K1 里复核是否该归 adapter)", phase: 'K1' },
23
+ { key: 'src/execution_registry.ts', cls: 'A', why: "执行登记 (幂等/在跑)", phase: 'K1' },
24
+ { key: 'src/tool_pool.ts', cls: 'A', why: "工具池 (调度侧; 不负责副作用)", phase: 'K1' },
25
+ { key: 'src/session_store.ts', cls: 'A', why: "Session 存取 (只读纯函数部分; 可变 Session 不在此册)", phase: 'K1' },
26
+ { key: 'src/cost_tracker.ts', cls: 'A', why: "用量计数 (K6 usage 记录会用到)", phase: 'K1' },
27
+ { key: 'src/models.ts', cls: 'A', why: "模型/能力描述 (capability registry)", phase: 'K1' },
28
+ { key: 'src/cost_hook.ts', cls: 'A', why: "用量钩子", phase: 'K1' },
29
+ { key: 'src/tools/WalletTools/', cls: 'B', why: "WalletTools: 经 Tool Capability 接入", phase: 'K7' },
30
+ { key: 'src/tools/SafeSDK/', cls: 'B', why: "SafeSDK", phase: 'K7' },
31
+ { key: 'src/tools/PolymarketSDK/', cls: 'B', why: "PolymarketSDK", phase: 'K7' },
32
+ { key: 'src/tools/OpenCLI/', cls: 'B', why: "OpenCLI", phase: 'K7' },
33
+ { key: 'src/remote/', cls: 'C', why: "remote/ssh/teleport 占位实现 —— 不进核心", phase: '第一批' },
34
+ { key: 'src/remote_runtime.ts', cls: 'C', why: "假连接/假成功的 remote runtime (leo 第一批点名的清理对象)", phase: '第一批' },
35
+ { key: 'src/upstream_proxy/', cls: 'C', why: "上游代理占位", phase: '第一批' },
36
+ { key: 'src/_archive_helper.ts', cls: 'C', why: "archive 辅助 (不进运行时包)", phase: '第一批' },
37
+ { key: 'src/reference_data/', cls: 'C', why: "reference 数据 (不进运行时包)", phase: '第一批' },
38
+ { key: 'src/parity_audit.ts', cls: 'C', why: "迁移期 parity 审计 (一次性)", phase: '第一批' },
39
+ { key: 'src/migrations/', cls: 'C', why: "迁移脚本 (一次性)", phase: '第一批' },
40
+ { key: 'src/native_ts/', cls: 'C', why: "旧移植层 (native ts)", phase: '第一批' },
41
+ { key: 'src/screens/', cls: 'C', why: "TUI 屏", phase: '第一批' },
42
+ { key: 'src/components/', cls: 'C', why: "TUI 组件", phase: '第一批' },
43
+ { key: 'src/keybindings/', cls: 'C', why: "键位表", phase: '第一批' },
44
+ { key: 'src/vim/', cls: 'C', why: "vim 模式", phase: '第一批' },
45
+ { key: 'src/voice/', cls: 'C', why: "语音", phase: '第一批' },
46
+ { key: 'src/output_styles/', cls: 'C', why: "输出样式", phase: '第一批' },
47
+ { key: 'src/moreright/', cls: 'C', why: "终端渲染 (移植层)", phase: '第一批' },
48
+ { key: 'src/buddy/', cls: 'C', why: "彩蛋壳", phase: '第一批' },
49
+ { key: 'src/assistant/', cls: 'C', why: "助手壳", phase: '第一批' },
50
+ { key: 'src/ink.ts', cls: 'C', why: "ink 渲染入口", phase: '第一批' },
51
+ { key: 'src/setup.ts', cls: 'C', why: "移植层 setup", phase: '第一批' },
52
+ { key: 'src/system_init.ts', cls: 'C', why: "移植层初始化", phase: '第一批' },
53
+ { key: 'src/deferred_init.ts', cls: 'C', why: "移植层延迟初始化", phase: '第一批' },
54
+ { key: 'src/bootstrap_graph.ts', cls: 'C', why: "移植层依赖图", phase: '第一批' },
55
+ { key: 'src/bootstrap/', cls: 'C', why: "移植层 bootstrap", phase: '第一批' },
56
+ { key: 'src/command_graph.ts', cls: 'C', why: "移植层命令图", phase: '第一批' },
57
+ { key: 'src/commands.ts', cls: 'C', why: "移植层命令表", phase: '第一批' },
58
+ { key: 'src/direct_modes.ts', cls: 'C', why: "移植层直接模式", phase: '第一批' },
59
+ { key: 'src/entrypoints/', cls: 'C', why: "移植层入口", phase: '第一批' },
60
+ { key: 'src/cli/', cls: 'C', why: "移植层 CLI", phase: '第一批' },
61
+ { key: 'src/schemas/', cls: 'C', why: "移植层 schema", phase: '第一批' },
62
+ { key: 'src/services/', cls: 'C', why: "移植层服务", phase: '第一批' },
63
+ { key: 'src/server/', cls: 'C', why: "移植层 server", phase: '第一批' },
64
+ { key: 'src/state/', cls: 'C', why: "移植层 state", phase: '第一批' },
65
+ { key: 'src/memdir/', cls: 'C', why: "移植层 memory dir", phase: '第一批' },
66
+ { key: 'src/history.ts', cls: 'C', why: "移植层 history", phase: '第一批' },
67
+ { key: 'src/context.ts', cls: 'C', why: "移植层 context", phase: '第一批' },
68
+ { key: 'src/prefetch.ts', cls: 'C', why: "移植层 prefetch", phase: '第一批' },
69
+ { key: 'src/query.ts', cls: 'C', why: "移植层 query", phase: '第一批' },
70
+ { key: 'src/bridge/', cls: 'C', why: "移植层 bridge", phase: '第一批' },
71
+ { key: 'src/coordinator/', cls: 'C', why: "移植层 coordinator 壳", phase: '第一批' },
72
+ { key: 'src/plugins/', cls: 'C', why: "移植层插件", phase: '第一批' },
73
+ { key: 'src/types/', cls: 'C', why: "移植层类型", phase: '第一批' },
74
+ { key: 'src/utils/', cls: 'C', why: "移植层 utils", phase: '第一批' },
75
+ { key: 'src/constants/', cls: 'C', why: "移植层常量", phase: '第一批' },
76
+ { key: 'src/runtime/', cls: 'C', why: "移植层 runtime", phase: '第一批' },
77
+ { key: 'src/hooks/', cls: 'C', why: "移植层 hooks (与主仓 hooks-engine 无关)", phase: '第一批' },
78
+ { key: 'src/dynamic-tool-loader.ts', cls: 'C', why: "动态工具加载 (占位)", phase: '第一批' },
79
+ { key: 'src/tools.ts', cls: 'C', why: "移植层 tools 聚合", phase: '第一批' },
80
+ { key: 'src/transcript.ts', cls: 'C', why: "移植层 transcript", phase: '第一批' },
81
+ { key: 'src/index.ts', cls: 'C', why: "移植层包入口 (Kernel 不用; 主仓用的是包入口的公开导出)", phase: '第一批' },
82
+ { key: 'src/port_manifest.ts', cls: 'C', why: "移植清单", phase: '第一批' },
83
+ { key: 'src/platform.d.ts', cls: 'C', why: "类型垫片", phase: '第一批' },
84
+ { key: 'dist/', cls: 'BUILD', why: "构建产物 (git 忽略, 不入 git) + **运行期必需的 reference_data/*.json 快照**; 不入三层名单, 单独冻结计数", phase: '第一批' },
85
+ { key: 'tests/', cls: 'C', why: "constraint-runtime 自带测试 (4 文件) —— 但 vitest 配置 `**/constraint-runtime/**` 把整个目录排除了 ⇒ **它们从来不跑** (K1 真发现)", phase: '第一批' },
86
+ { key: 'package.json', cls: 'META', why: "包元数据", phase: 'K1' },
87
+ { key: 'package-lock.json', cls: 'META', why: "锁文件", phase: 'K1' },
88
+ { key: 'tsconfig.json', cls: 'META', why: "包 tsconfig", phase: 'K1' },
89
+ { key: 'node_modules/', cls: 'META', why: "依赖 (不入仓判断)", phase: 'K1' },
90
+ ];
91
+ /** 扫描基座 (相对 src/) + 不算源码的子树 */
92
+ export const CONSTRAINT_ROOT = 'constraint-runtime/';
93
+ export const CONSTRAINT_NON_SOURCE = ['dist/', 'node_modules/'];
94
+ /** 冻结量: 源码 / 空壳 / 构建产物 (棘轮: 只许减) */
95
+ export const CONSTRAINT_SRC_FILES = 59;
96
+ export const CONSTRAINT_SRC_LINES = 1925;
97
+ export const CONSTRAINT_STUB_FILES = 5;
98
+ export const CONSTRAINT_STUB_LINES = 12;
99
+ export const CONSTRAINT_DIST_FILES = 54;
100
+ export const CONSTRAINT_DIST_LINES = 783;
101
+ /**
102
+ * dist/reference_data/*.json —— **快照数据, 运行期真被读**:
103
+ * tools.ts 启动时读 tools_snapshot.json → PORTED_TOOLS (实测 **184 条**) → executeToolFromSnapshot 按 source_hint 动态 import;
104
+ * commands.ts 同理读 commands_snapshot.json。
105
+ * **陷阱**: CR 的 build 只有 `tsc`, 不复制 .json ⇒ 任何 `rm -rf dist && tsc` 都会静默丢掉它们
106
+ * (PORTED_TOOLS 变 0, 只有一行 warn, 无报错) —— 这是"静默降级路径", 见 kernel-constraint.test.ts 的 K1-e 门。
107
+ */
108
+ export const CONSTRAINT_DIST_DATA_JSON = 32;
109
+ /** 各层文件数 / 行数冻结值 */
110
+ export const CONSTRAINT_CLASS_FILES = { "A": 13, "C": 22, "B": 24 };
111
+ export const CONSTRAINT_CLASS_LINES = { "A": 352, "C": 776, "B": 797 };
112
+ export const A_ENTRY_USES = [
113
+ { key: 'src/constraint/', usedVia: 'pkg-entry', evidence: 'agents/constraint-layer.ts 取 ToolPermissionContext / BudgetTracker' },
114
+ { key: 'src/skills/', usedVia: 'pkg-entry', evidence: 'pi-sdk.ts / skill-loader.ts / bollharness skill-adapter 取 SkillRegistry' },
115
+ { key: 'src/agent/', usedVia: 'pkg-entry', evidence: 'pi-sdk.ts 取 AgentCoordinator' },
116
+ { key: 'src/thinking/', usedVia: 'pkg-entry', evidence: 'pi-sdk.ts 取 DeepThinkingEngine' },
117
+ { key: 'src/session_store.ts', usedVia: 'pkg-entry', evidence: 'pi-sdk.ts / pi-sdk-session-manager.ts 取 Session/saveSession/loadSession' },
118
+ { key: 'src/execution_registry.ts', usedVia: 'unused-debt', evidence: '主仓 0 引用 —— 待复核' },
119
+ { key: 'src/tool_pool.ts', usedVia: 'unused-debt', evidence: '主仓 0 引用 —— 待复核' },
120
+ { key: 'src/cost_tracker.ts', usedVia: 'unused-debt', evidence: '主仓 0 引用; K6 的 usage 记录若要用则转 pkg-entry' },
121
+ { key: 'src/cost_hook.ts', usedVia: 'unused-debt', evidence: '主仓 0 引用 —— 待复核' },
122
+ { key: 'src/models.ts', usedVia: 'unused-debt', evidence: '主仓 0 引用; 能力描述可与主仓 provider-registry 合并' },
123
+ ];
124
+ /** A 类里「主仓 0 引用」的条数冻结值 (棘轮: 只许减) */
125
+ export const A_UNUSED_DEBT_FROZEN_AT = 5;
126
+ export const CONSTRAINT_USES = [
127
+ { file: 'agents/constraint-layer.ts', target: '__pkg_entry__', count: 1, kind: 'prod', cls: 'A' },
128
+ { file: 'agents/pi-sdk-session-manager.ts', target: '__pkg_entry__', count: 1, kind: 'prod', cls: 'A' },
129
+ { file: 'agents/pi-sdk-tools.ts', target: 'tools/PolymarketSDK/cancelOrder', count: 2, kind: 'prod', cls: 'B' },
130
+ { file: 'agents/pi-sdk-tools.ts', target: 'tools/PolymarketSDK/createOrder', count: 2, kind: 'prod', cls: 'B' },
131
+ { file: 'agents/pi-sdk-tools.ts', target: 'tools/PolymarketSDK/getMarket', count: 2, kind: 'prod', cls: 'B' },
132
+ { file: 'agents/pi-sdk-tools.ts', target: 'tools/PolymarketSDK/getOrders', count: 2, kind: 'prod', cls: 'B' },
133
+ { file: 'agents/pi-sdk-tools.ts', target: 'tools/PolymarketSDK/listMarkets', count: 2, kind: 'prod', cls: 'B' },
134
+ { file: 'agents/pi-sdk-tools.ts', target: 'tools/SafeSDK/deploySafe', count: 2, kind: 'prod', cls: 'B' },
135
+ { file: 'agents/pi-sdk.ts', target: '__pkg_entry__', count: 2, kind: 'prod', cls: 'A' },
136
+ { file: 'agents/skill-loader.ts', target: '__pkg_entry__', count: 1, kind: 'prod', cls: 'A' },
137
+ { file: 'bollharness-integration/gate-state-machine.ts', target: '__pkg_entry__', count: 1, kind: 'prod', cls: 'A' },
138
+ { file: 'bollharness-integration/skill-adapter.ts', target: '__pkg_entry__', count: 1, kind: 'prod', cls: 'A' },
139
+ { file: 'test/econ-integration.test.ts', target: 'tools/PolymarketSDK/econ-integration', count: 1, kind: 'test', cls: 'B' },
140
+ { file: 'test/wallet-polymarket-verify.test.ts', target: 'tools/PolymarketSDK/cancelOrder', count: 1, kind: 'test', cls: 'B' },
141
+ { file: 'test/wallet-polymarket-verify.test.ts', target: 'tools/PolymarketSDK/clobShared', count: 1, kind: 'test', cls: 'B' },
142
+ { file: 'test/wallet-polymarket-verify.test.ts', target: 'tools/PolymarketSDK/createOrder', count: 1, kind: 'test', cls: 'B' },
143
+ { file: 'test/wallet-polymarket-verify.test.ts', target: 'tools/PolymarketSDK/getMarket', count: 1, kind: 'test', cls: 'B' },
144
+ { file: 'test/wallet-polymarket-verify.test.ts', target: 'tools/PolymarketSDK/getOrders', count: 1, kind: 'test', cls: 'B' },
145
+ { file: 'test/wallet-polymarket-verify.test.ts', target: 'tools/PolymarketSDK/listMarkets', count: 1, kind: 'test', cls: 'B' },
146
+ { file: 'test/wallet-polymarket-verify.test.ts', target: 'tools/WalletTools/createWallet', count: 1, kind: 'test', cls: 'B' },
147
+ { file: 'test/wallet-polymarket-verify.test.ts', target: 'tools/WalletTools/getBalance', count: 1, kind: 'test', cls: 'B' },
148
+ { file: 'test/wallet-polymarket-verify.test.ts', target: 'tools/WalletTools/importWallet', count: 1, kind: 'test', cls: 'B' },
149
+ { file: 'test/wallet-polymarket-verify.test.ts', target: 'tools/WalletTools/signMessage', count: 1, kind: 'test', cls: 'B' },
150
+ ];
151
+ export const B_DIRECT_IMPORT_DEBT = [
152
+ { file: 'agents/pi-sdk-tools.ts', target: 'tools/PolymarketSDK/cancelOrder', count: 2, payDownIn: 'K7' },
153
+ { file: 'agents/pi-sdk-tools.ts', target: 'tools/PolymarketSDK/createOrder', count: 2, payDownIn: 'K7' },
154
+ { file: 'agents/pi-sdk-tools.ts', target: 'tools/PolymarketSDK/getMarket', count: 2, payDownIn: 'K7' },
155
+ { file: 'agents/pi-sdk-tools.ts', target: 'tools/PolymarketSDK/getOrders', count: 2, payDownIn: 'K7' },
156
+ { file: 'agents/pi-sdk-tools.ts', target: 'tools/PolymarketSDK/listMarkets', count: 2, payDownIn: 'K7' },
157
+ { file: 'agents/pi-sdk-tools.ts', target: 'tools/SafeSDK/deploySafe', count: 2, payDownIn: 'K7' },
158
+ ];
159
+ export const B_DIRECT_IMPORT_FROZEN_AT = 12;
160
+ /**
161
+ * 引用台账的扫描面**排除名单** (冻结, 只许减):
162
+ * 本门自己的测试文件里有"人造引用"探针串 (判别力自证用), 不排掉它就会被当成一条真引用
163
+ * —— 这就是本仓那条老规矩: 拿子串当判据前, 先排除自己刚写的东西。
164
+ */
165
+ export const CONSTRAINT_SCAN_EXCLUSIONS = ['test/kernel-*.test.ts'];
@@ -0,0 +1,32 @@
1
+ /**
2
+ * **K1 删除就绪台账** —— 每个候选对象给出 verdict + **引用证据**, 不许写「看起来没用」。
3
+ *
4
+ * leo 的五个删除条件 (缺一不许删): ① 有唯一替代路径 ② 全仓无有效 import / 动态引用 / 路由引用
5
+ * ③ 真跑覆盖旧能力 ④ 一次完整回归 + 一次故障恢复 ⑤ 留可回滚提交点。
6
+ *
7
+ * 本文件是 K1 第 ① 步的真实产出: **核验推翻了直觉排序** —— 原以为 dist/ 与 33 个空壳最该先删,
8
+ * 实测两者都是**运行期依赖** (dist 是 main/exports 目标; 33 个 stub 引 reference_data 快照)。
9
+ * 真正 0 引用的只有 2 个 15 行 stub。
10
+ *
11
+ * 判据: src/test/kernel-deletion.test.ts (verdict 必须与盘上引用面**同步**, 不许烂成借口)。
12
+ */
13
+ export const DELETION_VERDICTS = [
14
+ { group: 'CR 源: migrations/', target: 'src/constraint-runtime/src/migrations/', verdict: 'done', blockers: [], reason: "15 行 stub; 仓内(含 constraint-runtime 自身与 dist) 0 引用; **不在 `CR/src/index.ts` 的导出面** ⇒ 可直删" },
15
+ { group: 'CR 源: remote/', target: 'src/constraint-runtime/src/remote/', verdict: 'done', blockers: [], reason: "15 行 stub; 0 引用; 不在导出面 ⇒ 可直删" },
16
+ { group: 'CR/dist 构建产物 (89 文件/1164 行)', target: 'src/constraint-runtime/dist/', verdict: 'blocked', blockers: [{ file: 'src/agents/pi-sdk-tools.ts', why: "动态 import ../constraint-runtime/dist/tools/{PolymarketSDK/*,SafeSDK/deploySafe}.js (6 处)" }, { file: 'Dockerfile', why: "第167行把 src/constraint-runtime/dist COPY 进 node_modules/@bolloon/constraint-runtime/dist" }, { file: 'src/constraint-runtime/package.json', why: "main/exports 指向 dist/index.js; files=['dist/**/*']" }], reason: "**dist 才是运行期目标** (源码树不是) ⇒ 删 dist 直接断掉 B 类工具与包入口。必须先做完 K7 (B 类改 Tool Capability) 才有资格谈" },
17
+ { group: 'CR 源: reference_data/ (子系统快照数据)', target: 'src/constraint-runtime/src/reference_data/', verdict: 'blocked', blockers: [{ file: 'src/constraint-runtime/src/tools.ts', why: "同目录 tools_snapshot.json 是运行期派发台账 (PORTED_TOOLS + executeToolFromSnapshot 按 source_hint import) ⇒ 整个目录不能整删; subsystems/*.json 现在是**孤立数据** (读取者 _archive_helper 已删), 处置要单独决定" }], reason: "26 个存档壳删掉后 subsystems/*.json 只剩数据; 同目录混着运行期台账 ⇒ 需按文件分别判, 不是目录级删除" }, { group: 'CR 源: parity_audit.ts / remote_runtime.ts / native_ts/ / upstream_proxy/', target: 'src/constraint-runtime/src/parity_audit.ts', verdict: 'blocked', blockers: [{ file: 'src/constraint-runtime/src/index.ts', why: "第21-22行 re-export (runParityAudit / runRemoteMode / runSshMode / runTeleportMode)" }, { file: 'src/constraint-runtime/dist/index.js', why: "编译副本同样 re-export ⇒ 删源码还要重建 dist" }], reason: "可达包入口 ⇒ 删除要**同时改 index.ts + 重建 dist**, 属 K1-④ 的活, 不是纯删" },
18
+ { group: 'src/bollharness/ (另一个项目的镜像)', target: 'src/bollharness/', verdict: 'blocked', blockers: [{ file: 'scripts/smoke-esm.mjs', why: "第38行引用 dist/bollharness/src/scripts/context_router.js" }, { file: 'scripts/gen-copyright-source.ts', why: "第25行明写: src/bollharness 是**第三方 vendored 框架** (版权属 bollharness contributors), 不进版权登记" }], reason: "**第三方 vendored 框架** (不是 Bolloon 代码) + 版权归属未处置 + smoke 脚本引用 ⇒ 处置要先定它的归属, 属第一批「审查」而非机械化删除" },
19
+ { group: 'K1 第②步批二: 26 个移植存档壳', target: 'src/constraint-runtime/src/<26 个移植存档壳>/index.ts', verdict: 'done', blockers: [], reason: "包入口闭包外 + 主仓 0 引用 + 快照 0 点名; 自述为 Python placeholder package; 已删 (记录见 DELETION_LEDGER)" },
20
+ { group: 'K1 第②步批二: _archive_helper', target: 'src/constraint-runtime/src/_archive_helper.ts', verdict: 'done', blockers: [], reason: "只被 26 个存档壳调用; 随它们一起删" },
21
+ { group: 'K1 第②步批二: 6 个根级移植残留', target: 'src/constraint-runtime/src/<6 个根级移植残留>.ts', verdict: 'done', blockers: [], reason: "cost_hook/execution_registry/ink/port_manifest/query/system_init; 0 引用 0 点名; 已删" },
22
+ // ★ 下面这条是被编译期抓回来的一类: **环境声明 .d.ts 不是"被 import"的对象, 但它是编译期依赖**
23
+ { group: 'K1 第②步批二: platform.d.ts (撤回!)', target: 'src/constraint-runtime/src/platform.d.ts', verdict: 'not-deletable', blockers: [{ file: 'src/constraint-runtime/src/setup.ts', why: "靠 `declare module 'platform'` 编译; 删掉即 TS7016" }], reason: "**判错过一次**: 静态可达性看不见环境声明 ⇒ 删后 CR tsc 红 (TS7016), 已恢复。判据对 .d.ts 一律不判 ready" },
24
+ ];
25
+ /** 五个删除条件的机器可核验部分 (人/真跑承担的部分写在删除记录的 acceptance 字段) */
26
+ export const DELETION_CONDITIONS = [
27
+ '① 有唯一替代路径',
28
+ '② 全仓无有效 import / 动态引用 / CLI·Web 路由引用',
29
+ '③ 真跑已覆盖旧路径对应能力',
30
+ '④ 一次完整回归 + 一次故障恢复',
31
+ '⑤ 留可回滚提交点 (不丢历史)',
32
+ ];
@@ -0,0 +1,60 @@
1
+ /**
2
+ * **K6 —— ModelRuntime 台账 + 门的数据面**。
3
+ *
4
+ * K6 的目标 (路线图原文, 不许跳): 以 `ModelRuntime.acquire(modelSnapshot)` 为**只读**入手的多供应商运行时
5
+ * (并发 · 连接池 · timeout · cancellation · 429 退避 · circuit breaker · capability 检查 · provider fallback · usage 记录),
6
+ * **已有的 `selectModel` / registry / catalog / Run snapshot 继续保留, 不重做**。
7
+ *
8
+ * 通用判据 (K2 实操中拦回过一次 assistant 的实现): **新层出现后, 旧写口的调用点数只许不变或减少。**
9
+ * —— 所以 K6 的第一件事不是写运行时, 而是把"旧写口"**数清楚并冻结**, 让"只读"这件事可判、可回退检测。
10
+ */
11
+ /**
12
+ * **旧写口名册 (冻结)** —— 口径: 全仓 (排除 `test/` 与 `kernel/`) 里 `name(` 的匹配次数, **去掉含 `function name` 的声明行**。
13
+ * 判据用同一口径从盘上重算 ⇒ 增 = 新层在偷偷改旧状态 (回退) · 减 = 改了盘没改账。
14
+ */
15
+ export const MODEL_WRITE_PORTS = [
16
+ { name: 'setCustomProviderSnapshot', module: 'llm/provider-registry.ts', callSites: 5 },
17
+ { name: 'addCustomProvider', module: 'llm/custom-provider-store.ts', callSites: 0, note: '主仓零调用 (仅测试/未来向导用) —— 只许不变或减' },
18
+ { name: 'updateCustomProvider', module: 'llm/custom-provider-store.ts', callSites: 0, note: '主仓零调用' },
19
+ { name: 'removeCustomProvider', module: 'llm/custom-provider-store.ts', callSites: 0, note: '主仓零调用' },
20
+ { name: 'writeSessionSelection', module: 'llm/model-selection.ts', callSites: 1 },
21
+ { name: 'clearSessionSelection', module: 'llm/model-selection.ts', callSites: 2 },
22
+ { name: 'resetModelSelection', module: 'llm/model-selection.ts', callSites: 1 },
23
+ { name: 'setSystemPrependProvider', module: 'llm/pi-ai.ts', callSites: 1 },
24
+ { name: 'clearSystemPromptCache', module: 'llm/pi-ai.ts', callSites: 1 },
25
+ ];
26
+ /** 合计冻结值 (棘轮: 只许不变或减少; 要加必须同时改这里 ⇒ diff 里一次显式动作) */
27
+ export const MODEL_WRITE_PORTS_FROZEN_AT = 11;
28
+ /** `acquire` 的**只读**要求 (写成数据, 判据与实现共用) */
29
+ export const MODEL_RUNTIME_ACQUIRE_RULE = {
30
+ readOnly: true,
31
+ rule: '`acquire(modelSnapshot)` 只读: 不许改 provider 配置 / API key / 默认 URL / Global model / Run snapshot',
32
+ ratchet: '新层出现后, 旧写口的调用点数只许不变或减少 (增 = 回退)',
33
+ };
34
+ export const MODEL_RUNTIME_CAPABILITIES = [
35
+ { key: 'multi-provider-concurrency', why: '多供应商并发调用 (各 provider 各自限流)', status: 'done' },
36
+ { key: 'connection-pool', why: '连接复用 (keep-alive), 不每次新建', status: 'done' },
37
+ { key: 'timeout', why: '单次调用超时 (按 snapshot 的预算)', status: 'done' },
38
+ { key: 'cancellation', why: '取消传播 (AbortSignal 透传)', status: 'done' },
39
+ { key: 'rate-limit-backoff', why: '429 退避 (指数 + 抖动, 不许重试风暴)', status: 'done' },
40
+ { key: 'circuit-breaker', why: '连续失败熔断 (半开探测)', status: 'done' },
41
+ { key: 'capability-check', why: '能力检查 (该 provider 是否支持所需能力: 工具/vision/长上下文)', status: 'done' },
42
+ { key: 'provider-fallback', why: '失败回退到备用 provider (按 Run snapshot, 不改全局)', status: 'done' },
43
+ { key: 'usage-recording', why: 'usage 记录 (token/成本按 Run 记账)', status: 'done' },
44
+ ];
45
+ /** **明确不做** (路线图红线; 判据核这几条名字都在, 防止实现时越界) */
46
+ export const MODEL_RUNTIME_OUT_OF_SCOPE = [
47
+ '不自行改 provider 配置',
48
+ '不自行改 API key',
49
+ '不自行改默认 URL',
50
+ '不自行改 Global model',
51
+ '不自行改 Run snapshot',
52
+ ];
53
+ /** K6 进度 (与 K5 的 stage/container 同款: 声明未实现 ⇒ 运行时文件**必须不存在**) */
54
+ export const K6_PROGRESS = {
55
+ stage: 'capabilities-done',
56
+ runtimePath: 'kernel/model-runtime.ts',
57
+ /** 必须等于 `MODEL_RUNTIME_CAPABILITIES` 里 status==='done' 的条数 (判据机械核, 不许自报) */
58
+ capabilitiesDone: 9,
59
+ capabilitiesTotal: MODEL_RUNTIME_CAPABILITIES.length,
60
+ };