Replies: 1 comment
|
这三点的方向我基本同意。我倾向把最终模型拆成下面几层:
同时建议调整 WorkHub 的默认投递行为:
如果 steering message 尚未消费,Stop 可取消该 message。若已经并入 shared Turn,则无法只撤回它造成的影响。此时不应只返回模糊的 这样默认路径保持独立、可排队、可单独停止;只有用户主动 promote 为 steering 后,才进入共享执行语义。以后再增加意图识别,用于建议或自动触发 promote,不必阻塞当前阶段。 |
Uh oh!
There was an error while loading. Please reload this page.
The WorkHub authority model (ADR, #3492) draws a clear boundary: the Coordination Session owns the coordination conversation and its bounded delegation references, while the target ordinary Session owns concrete execution, recovery, and the authoritative execution transcript.
Coordination has since taken ownership of an execution fact it cannot observe: which delegations still hold stoppable work. Because it cannot observe execution directly, it approximates liveness through terminal records — and each approximation has grown machinery to compensate.
#4699 is correct and is not being asked to change. By removing two secondary authorities, it is what made this remaining drift visible.
Three things follow from that drift, in dependency order. I would like agreement on the reading before any of them becomes work.
1. Consolidate terminal record kinds into one retirement fact
Today a delegation link ends via three separate record kinds:
delegation_superseded,delegation_replacement_aborted, anddelegation_stop_resolved(whenoutcome !== 'not_owned'). To enumerate active assignments,readActiveWorkHubAssignmentsByTargetexecutes three point lookups per row just to ignore inactive links.This conflates two separate concepts: whether the link is dead, and how the correcting action ended. Action replay needs the latter; the link only needs the former. Distinct UI labels do not require separate record kinds.
One record kind would carry both:
Point lookups drop from three to one. The
outcome !== 'not_owned'condition ceases to be a reader-side special case and becomes an absence — nothing was retired, so no record is written. Record ids already in user workspaces cannot change, so the three legacy kinds would fold into this retirement fact at the read boundary.2. Return delegation liveness to the target Session
Today a delegation is active iff none of the three terminal records exists. Completion is not among them. The ADR states it outright:
A target Session finishing its work is a fact in that Session's own ledger. Coordination never learns it, so it cannot write a terminal record for it. Liveness is therefore reduced to "not explicitly killed": finished work reads as active forever, and callers that need the real answer ask execution per candidate through
readDelegationRetirement. Meanwhile candidate enumeration already readsmessage_admissions,session_messages, andcancelled_message_admissions— the three tables that carry exactly that state — and discards which one each row came from.The cost is measurable. An automated review on #4699 reported it and it was deferred deliberately, because every bounded variant is wrong and the terminal id is
sha256(delegationId), so the anti-join cannot be pushed into SQL. On 32 targets whose delegations are all terminal: 100 rows 3.3 ms, 1000 rows 32 ms, 6000 rows 194 ms, inside a synchronous read transaction.Liveness would instead be asked of the target Session:
readDelegationRetirementalready consults.3. Let the stop protocol name its delegation
Today
stop_workcarries onlytargetSessionId. When a Session holds more than one link, the Gate inspects execution across all of them and requires exactly one to still hold stoppable work, or fails with a conflict.The protocol answers the same question the other way for the same trust boundary.
stop_workcarries onlytargetSessionIdwhilereplacecarriesreplacesActionId; candidates already exposelatestDelegationActionId, andreplacealready consumes it. Stop omits it only because its branch runs before candidates are read — a call-order detail, not a capability the client lacks.Authorization is held by
confirmation: { kind: 'user_stop' }, outside strategy output. Naming is not authorization; the Gate revalidates the named link against durable state either way.If
stop_workcarriedstopsActionIdsourced fromlatestDelegationActionId, the Gate would validate it with a point lookup, andlistActiveAssignments, the competitor-retirement loop, and the sole-active-delegation proof would all lose their only reason to exist. With item 2 in place, the hot path above goes with them.Open question: does replacement have to kill the old work first?
Replacement cancels the old work before delegating anew, which is why
delegation_replacement_requested, the abort record, and the retire-then-admit compensation chain exist. If a correction were simply a new delegation, none of that would. Preserving user order is a real requirement, so this is a product decision rather than an architectural necessity — noted for a separate conclusion, not proposed for change here.Questions
replacealready uses, and drop Gate-side link inference?中文对照
按 #3492 划定的权威边界,Coordination 只拥有协调对话和委派引用,执行归 target Session。但它现在还拥有了一个自己观测不到的执行事实:哪些委派还持有可停止的活。三条待讨论,按依赖顺序:
终态合一。一条链接的死亡分成三种记录、三个前缀,读取时每行三次点查。合并成
delegation_retired { delegationId, reason },UI 的三种文案照样出得来。活跃性归还 target。target 干完活是它自己账本里的事,Coordination 学不到,只能把活跃定义成"没被显式杀掉"——已完成的委派永远读作活跃。而枚举时读的那三张 target 侧表本来就带着状态,现在被丢掉只取了 id。代价可测:全终态时 6000 行 194ms,跑在同步读事务里(fix(workhub): resolve WorkHub delegation linkage on demand #4699 上被 defer 的 P2)。
stop 应当指名。同一份协议里
replace带replacesActionId,stop_work只带targetSessionId;candidate 已经暴露latestDelegationActionId,replace也已经在用。要守的是授权,那已由confirmation守住,指名不是授权。stop 一旦指名,活跃集合、竞争者退役循环、唯一活跃证明连同上面那条热路径一起消失。请教两点:活跃性归 target 这个判断对吗?stop 是否应该和
replace对齐、改为显式指名?All reactions