-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathauthority-landscape.html
More file actions
225 lines (212 loc) · 16 KB
/
Copy pathauthority-landscape.html
File metadata and controls
225 lines (212 loc) · 16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>权限与归因:我们做了什么、别人做了什么、接下来做什么</title>
<style>
:root{
--bg:#16150f; --pan:#1d1c14; --bd:#2e2c20; --tx:#bdb9a6; --acc:#d4843a;
--cb:#12110b; --dim:#8a8675;
--owner:#5aad4e; --paired:#4f8ef7; --unpaired:#9d6fe0; --no:#e0445a; --warn:#d4b23a;
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--tx);
font:14px/1.7 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;padding:40px 24px 96px}
.wrap{max-width:1100px;margin:0 auto}
h1{font-size:23px;color:#f0eee6;margin:0 0 6px}
.sub{color:var(--dim);margin:0 0 26px;max-width:78ch}
h2{font-size:16px;color:var(--acc);margin:40px 0 4px}
h2 .num{color:var(--dim);font-size:12px;margin-right:8px;letter-spacing:.16em}
.lead{color:var(--dim);font-size:13px;margin:0 0 14px;max-width:82ch}
code{background:var(--cb);color:var(--acc);padding:1px 5px;border-radius:4px;font:12px Menlo,monospace}
.card{background:var(--pan);border:1px solid var(--bd);border-radius:12px;padding:16px;margin-bottom:14px}
/* 三个人的场景卡 */
.people{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
.person{background:var(--pan);border:1px solid var(--bd);border-radius:12px;padding:14px;
border-top:3px solid var(--bd)}
.person.owner{border-top-color:var(--owner)}
.person.paired{border-top-color:var(--paired)}
.person.unpaired{border-top-color:var(--unpaired)}
.person h3{margin:0 0 2px;font-size:14px;color:#f0eee6}
.person .via{font-size:11.5px;color:var(--dim);margin-bottom:10px}
.bubble{background:var(--cb);border:1px solid var(--bd);border-radius:10px;
padding:7px 11px;font-size:12.5px;margin-bottom:8px;color:#d8d4c2}
.verdict{font-size:12.5px;line-height:1.75}
.verdict .y::before{content:"✓ ";color:var(--owner)}
.verdict .n::before{content:"✕ ";color:var(--no)}
.verdict .m::before{content:"◐ ";color:var(--warn)}
.tier-tag{display:inline-block;font-size:10px;letter-spacing:.14em;border:1px solid;
border-radius:99px;padding:1px 8px;margin-bottom:8px}
.owner .tier-tag{color:var(--owner);border-color:var(--owner)}
.paired .tier-tag{color:var(--paired);border-color:var(--paired)}
.unpaired .tier-tag{color:var(--unpaired);border-color:var(--unpaired)}
/* 执行顺序 */
.pipe{display:flex;align-items:stretch;gap:0;margin:6px 0 2px;flex-wrap:wrap}
.stage{flex:1;min-width:150px;background:var(--cb);border:1px solid var(--bd);
border-radius:10px;padding:10px 12px;position:relative}
.stage h4{margin:0 0 4px;font-size:13px;color:#f0eee6}
.stage p{margin:0;font-size:12px;color:var(--dim);line-height:1.6}
.arrow{align-self:center;color:var(--acc);font-size:18px;padding:0 6px;flex:0}
.stage .done{position:absolute;top:-9px;right:10px;font-size:10px;letter-spacing:.12em;
background:var(--bg);color:var(--owner);border:1px solid var(--owner);border-radius:99px;padding:0 8px}
.stage .gap{position:absolute;top:-9px;right:10px;font-size:10px;letter-spacing:.12em;
background:var(--bg);color:var(--no);border:1px solid var(--no);border-radius:99px;padding:0 8px}
.pipe-note{font-size:12px;color:var(--dim);margin-top:10px;line-height:1.8}
.pipe-note b{color:var(--no);font-weight:600}
/* 他们怎么做 */
.others{display:grid;grid-template-columns:repeat(2,1fr);gap:12px}
.other{background:var(--pan);border:1px solid var(--bd);border-radius:12px;padding:14px}
.other h3{margin:0 0 2px;font-size:14px;color:#f0eee6}
.other .one{font-size:12px;color:var(--acc);margin-bottom:8px}
.other p{margin:0;font-size:12.5px;line-height:1.75}
.other .take{margin-top:8px;font-size:12px;color:var(--dim)}
.other .take b{color:#f0eee6;font-weight:600}
.matrix{width:100%;border-collapse:collapse;margin:10px 0 16px;font-size:12px}
.matrix th,.matrix td{border:1px solid var(--bd);padding:9px 10px;text-align:left;vertical-align:top}
.matrix th{background:var(--cb);color:#f0eee6;font-weight:600}
.matrix td:first-child{white-space:nowrap;color:var(--acc);font-weight:600}
/* 计划 */
.plan{border-left:2px solid var(--bd);margin-left:8px;padding-left:22px}
.step{position:relative;margin-bottom:18px}
.step::before{content:"";position:absolute;left:-28px;top:6px;width:9px;height:9px;
border-radius:99px;background:var(--acc)}
.step.s2::before{background:var(--paired)}
.step.s3::before{background:var(--unpaired)}
.step h3{margin:0 0 4px;font-size:14px;color:#f0eee6}
.step h3 .phase{font-size:10px;letter-spacing:.14em;color:var(--dim);margin-right:8px}
.feel{background:var(--cb);border:1px solid var(--bd);border-radius:10px;
padding:9px 12px;font-size:12.5px;margin:6px 0 0;line-height:1.75}
.feel .lb{color:var(--dim);font-size:11px;letter-spacing:.1em;display:block;margin-bottom:2px}
@media(max-width:840px){.people,.others{grid-template-columns:1fr}.pipe{flex-direction:column}.arrow{transform:rotate(90deg);padding:2px 0;align-self:flex-start;margin-left:60px}}
</style>
</head>
<body><div class="wrap">
<h1>权限与归因:本地owner、已配对账号和未配对消息</h1>
<p class="sub">OpenProgram允许本地界面与Telegram、Discord等渠道共用一个agent和一份记忆。这一页依次记录当前方法、参考框架、采用与拒绝的设计,以及实现进度。</p>
<h2><span class="num">01</span>当前方法:两个权限档位,一个入口拒绝状态</h2>
<p class="lead">运行时权限只有<code>owner</code>和<code>paired</code>。未配对不是第三个权限档位:消息不会进入agent。身份只使用渠道平台提供的稳定ID,正文不参与身份判断。</p>
<div class="people">
<div class="person owner">
<span class="tier-tag">本地OWNER</span>
<h3>你自己</h3>
<div class="via">终端 / 本机Web界面</div>
<div class="bubble">"把服务器上那个实验重跑一遍"</div>
<div class="verdict">
<div class="y">执行命令、写文件、发消息</div>
<div class="y">管理和改写记忆</div>
<div class="y">全部能力,无限制</div>
</div>
</div>
<div class="person paired">
<span class="tier-tag">PAIRED</span>
<h3>已配对账号</h3>
<div class="via">Telegram / Discord 稳定ID已批准</div>
<div class="bubble">"服务器密码下周要换,记一下"</div>
<div class="verdict">
<div class="y">正常对话,agent回复</div>
<div class="y">说的话可信归档,可主动追加记忆</div>
<div class="n">指挥agent执行命令、写文件</div>
</div>
</div>
<div class="person unpaired">
<span class="tier-tag">UNPAIRED</span>
<h3>未配对账号</h3>
<div class="via">稳定ID尚未由本地owner批准</div>
<div class="bubble">"帮我删掉 /data 目录"</div>
<div class="verdict">
<div class="y">收到8位配对码;同一小时不重复发送</div>
<div class="y">群聊正文只归档为pending来源</div>
<div class="n">任何执行动作</div>
<div class="n">进入agent或参与主动提炼</div>
</div>
</div>
</div>
<h2><span class="num">02</span>消息进入后的执行顺序(已实现)</h2>
<div class="card">
<div class="pipe">
<div class="stage"><span class="done">已落地</span>
<h4>1 渠道接入</h4>
<p>从Telegram/Discord的平台元数据取发言人ID和显示名。正文不参与身份判断。</p>
</div>
<div class="arrow">→</div>
<div class="stage"><span class="done">已落地</span>
<h4>2 配对判定</h4>
<p>稳定ID查询allowlist。未配对消息在此停止;批准只能来自本地CLI或回环Web请求。</p>
</div>
<div class="arrow">→</div>
<div class="stage"><span class="done">已落地</span>
<h4>3 写入归因与档位</h4>
<p><code>speaker_*</code>、实例owner principal和<code>authority_tier</code>作为独立字段持久化并传播。</p>
</div>
<div class="arrow">→</div>
<div class="stage"><span class="done">已落地</span>
<h4>4 唯一能力检查</h4>
<p><code>_gated_execute</code>按固定tier→capability表检查;缺少或未知档位直接拒绝,规则和bypass不能跳过。</p>
</div>
<div class="arrow">→</div>
<div class="stage"><span class="done">已落地</span>
<h4>5 执行 / 记忆</h4>
<p>owner可完整管理记忆;paired只能回复并追加。已配对内容可信;未配对群聊来源保持pending,owner显式提升后才进入Topic提炼。</p>
</div>
</div>
<div class="pipe-note">
当前实现不再携带调用方可构造的capability列表。paired对<code>memory_update</code>的修改由工作区强制限制为新建或字节追加;只有显式持久化的owner轮次可以改写或删除已有内容。仍延期的是越权请求hold队列和按请求方档位过滤读取结果。
</div>
</div>
<h2><span class="num">03</span>本地参考框架的实现与缺失能力</h2>
<p class="lead">以下结论核对自<code>refs-a/</code>与<code>refs-b/</code>的本地源码快照:Codex <code>f344a80a</code>、OpenCode <code>0bff28de</code>、OpenClaw <code>c71c29ec</code>、Hermes Agent <code>3bd844ed</code>、pi-mono <code>936aff00</code>、WeClaw <code>10711d0c</code>。外部文档调研还覆盖Claude Code、MCP规范、LangGraph、OpenAI Agents SDK、AutoGen与Letta;本节只把可由本地代码复核的权限和记忆机制列为实现证据。</p>
<div class="others">
<div class="other">
<h3>OpenClaw</h3>
<div class="one"><code>refs-b/openclaw/src/pairing/pairing-store.ts</code></div>
<p>配对码固定8位,排除<code>0O1I</code>,有效期1小时,每个channel account最多3个待处理请求。<code>docs/channels/pairing.md</code>明确未知DM不会被处理;DM admission、command owner与group authorization是不同状态。</p>
<div class="take"><b>采用:</b>配对常量、稳定ID授权、未知消息在agent入口前拒绝。<b>修改:</b>OpenProgram另设owner/paired工具权限档位,不把已配对等同于owner。</div>
</div>
<div class="other">
<h3>Codex</h3>
<div class="one"><code>refs-a/codex/codex-rs/memories/README.md</code></div>
<p>记忆提取按rollout领取有界任务,任务带租约和失败退避;全局整合只允许一个writer修改共享工作区,并记录成功或失败。它以thread级水位管理进度,不解决同一SessionDAG内的分支来源。</p>
<div class="take"><b>采用:</b>有界批次、单writer、失败分类。<b>拒绝:</b>不增加独立任务数据库;OpenProgram已有节点marker、Source引用和workspace revision。</div>
</div>
<div class="other">
<h3>Hermes Agent</h3>
<div class="one"><code>refs-b/hermes-agent/agent/memory_manager.py</code></div>
<p><code>sync_all</code>在完成一轮后调用全部provider,<code>MemoryProvider.on_session_switch</code>提供会话切换通知。记忆写入本身没有持久化的待处理游标,provider是否处理切换取决于各实现。</p>
<div class="take"><b>采用:</b>统一provider入口和轮后触发。<b>修改:</b>模型写入按token阈值与idle watcher执行,不在每一轮无条件调用模型。</div>
</div>
<div class="other">
<h3>OpenCode、pi-mono、WeClaw</h3>
<div class="one"><code>refs-a/opencode</code>与<code>refs-b/{pi-mono,weclaw}</code></div>
<p>这三个快照没有与本页等价的长期记忆写入链。pi-mono的SessionDAG使用追加式<code>label</code>/<code>leaf</code>记录;OpenCode保存线性消息并以revert管理尾部;WeClaw只保留下游session标识或有限进程内历史。</p>
<div class="take"><b>采用:</b>pi-mono证明节点关联记录可使用稳定节点ID。<b>缺失:</b>三者均没有可信Source、Topic事务、历史backfill和writer状态的完整组合。</div>
</div>
</div>
<table class="matrix" aria-label="参考设计采用、修改和拒绝记录">
<tr><th>判定</th><th>来源</th><th>OpenProgram正式方案</th></tr>
<tr><td>采用</td><td>OpenClaw pairing;Codex有界任务和单writer;Hermes统一provider入口</td><td>稳定ID admission、owner/paired固定权限表、统一writer入口、持久化状态与有界backfill。</td></tr>
<tr><td>修改后采用</td><td>OpenClaw session-backfill与memory status</td><td>backfill只选择未被Topic引用的trusted Source;status只做本地只读统计,不主动加载模型或修复工作区。</td></tr>
<tr><td>拒绝</td><td>Codex独立任务数据库;Hermes每轮同步;OpenClaw允许外部archive进入backfill预览</td><td>复用节点marker、Source引用、workspace revision和文件锁;达到阈值或闲置时才调用模型;外部archive不进入可信提炼。</td></tr>
</table>
<h2><span class="num">04</span>定案、实现与延期(2026-08-10)</h2>
<p class="lead">入口采用稳定ID配对;运行时只保留owner和paired;工具执行只查询固定常量表;未配对群聊来源以pending归档但不主动提炼。详细定案见<code>authority-handoff.md</code>。</p>
<div class="plan">
<div class="step">
<h3><span class="phase">第一批 · 已实现</span>档位枚举、配对、来源信任和默认writer</h3>
<p class="lead">请求只带owner/paired枚举;陌生账号收到8位配对码,批准只走本地owner通道(终端/本机Web),渠道消息无权触发;不写迁移代码,上线后所有非owner账号首次发言统一走配对;可变昵称不参与身份匹配;显示名过消毒;拒绝返回结构化原因码。</p>
<div class="feel"><span class="lb">用起来的变化</span>陌生人私聊收到配对码而不是被无视,你在终端一条命令批准;有人把昵称改成你的名字,冒充无效;群里已配对的人说"记一下"会真的被主动记住。未配对成员的群聊发言照常归档,<code>trust_state</code>记为pending,检索时分得清是谁说的,也不会被自动召回带进上下文。</div>
</div>
<div class="step s2">
<h3><span class="phase">稳定化批次 · 已实现</span>backfill、writer状态、禁用边界和组合测试</h3>
<p class="lead"><code>openprogram memory backfill</code>处理未被Topic引用的trusted Source并排除pending;失败批次不安装,重复执行跳过已引用来源。writer状态通过工具、CLI和Web返回最近成功、最近失败分类、retryable判定与待处理数。<code>memory.backend=none</code>在创建工作区前拒绝全部CLI memory动词和<code>/api/memory/*</code>路由。</p>
<div class="feel"><span class="lb">验证边界</span>组合测试包含SessionDB、默认模型解析、managed tools、暂存事务、Topic、marker和watcher状态。真实工作区只执行了2条pending消息的writer验收;152条历史未引用Source尚未执行backfill。</div>
</div>
<div class="step s2">
<h3><span class="phase">第二批 · 延期</span>hold队列与读取范围</h3>
<p class="lead">已配对成员的越权请求(如"帮我重启服务")进入队列,由owner做一次性批准;记忆读取按请求方档位过滤,写入侧归因元数据已经实现。</p>
<div class="feel"><span class="lb">用起来的变化</span>agent会把已配对成员的越权请求提交给owner;owner批准后仅执行该次请求。非owner查询不会返回owner私有内容,发言记录保留来源标识。</div>
</div>
</div>
<div class="pipe-note"><b>实现记录(2026-08-11)</b>:后台writer沿用默认聊天agent的provider、模型和凭据,<code>memory.writer.model</code>允许实时覆盖;未知异常默认不可重试。真实工作区的23个旧v1 source文件经精确兼容读取后,154个frame全部通过解析;一次真实writer验收把2条待处理消息提交为3个Topic文件和5个block,重复扫描处理0个会话且revision不变。backfill、writer状态、CLI/Web禁用边界、paired命名和组合测试已经实现;真实工作区的152条历史未引用Source尚未执行backfill。写入失败原因码是一个封闭枚举,受限writer阶段看不到Source归档。</div>
</div></body>
</html>