Skip to content

feat(runtime-host): integrate M3 domain ownership - #1190

Closed
M4n5ter wants to merge 37 commits into
apache:mainfrom
M4n5ter:feat/runtime-host-m3
Closed

feat(runtime-host): integrate M3 domain ownership#1190
M4n5ter wants to merge 37 commits into
apache:mainfrom
M4n5ter:feat/runtime-host-m3

Conversation

@M4n5ter

@M4n5ter M4n5ter commented Jul 18, 2026

Copy link
Copy Markdown
Member
English

Context

This is the non-production integration branch for the Runtime Host M3 work tracked by #1167 and designed under #853.

Its purpose is to validate cross-domain ownership, lifecycle, recovery, and multi-Client behavior before the implementation is extracted into independently reviewable upstream slices. This Draft is a reference and integration-evidence branch; it is not expected to merge as one change.

Integration evidence

The branch currently integrates and validates:

  • one authoritative Runtime Host per root, full-duplex Client sessions, bounded subscriptions, and canonical Session continuity;
  • kind-bound Storage authority and a production Headless root-kind boundary;
  • Host-owned closed operations for the retained Interactive domains, including Interaction, Message, Task Ledger, policy/configuration, Runtime Resources, native providers, and Session lifecycle;
  • draining for operations that settle, fail-stop owner isolation, old-Epoch recovery, and real graceful/SIGKILL successor journeys;
  • the invariant that the embedded Runtime remains the only production Interactive owner until the M5 atomic cutover.

This branch is now frozen for feature growth. Further changes should be limited to upstream synchronization or repairs needed to preserve its value as integration evidence. The bounded-shutdown foundation has landed independently in #1355; it is not inferred from this integration branch.

Slice extraction

Extraction starts from the latest main, not from this branch as a merge unit:

  1. full-duplex connection sessions and bounded outbound delivery (#1350), kind-bound Storage authority and the Headless boundary (#1354), bounded shutdown with process fail-stop (#1355), and protocol/dispatcher plus root-admission foundations (#1356) have merged;
  2. the Message authority foundation (#1357) and canonical Session projection and continuity (#1358) have merged;
  3. Interaction authority (#1359) is Ready after rebasing onto current main and revalidating the complete slice;
  4. Runtime Policy authority (#1401) has merged independently: canonical contracts, lease-bound CAS, redacted credential authority, typed Host operations, and backend activation/invalidation;
  5. Artifact authority (#1503) is Ready: canonical identity, atomic publication/recovery, exact retry, revision-pinned query, tombstone/purge, and protected evidence;
  6. Task Ledger authority (#1504) is Ready: lease-authenticated canonical reader/writer, Runtime TaskLedgerStore port, bounded revision-pinned Host query, and conservative resume trust;
  7. pending-start root-execution cancellation and Hosted graph composition remain explicit follow-up slices after feat(runtime-host): establish message authority foundation #1357, rather than partial capabilities claimed by Message authority;
  8. the remaining Session-core dependency chain then continues through Interaction -> hosted execution -> automation / goal, while complete dependency-independent authority verticals can proceed in parallel.

This is an initial dependency map, not a fixed PR count. Domain completeness matters more than minimizing each diff. Mixed integration commits are re-sliced by ownership rather than cherry-picked wholesale. Independent slices open Ready; a slice remains Draft only while it genuinely depends on an unmerged prerequisite.

The stale same-version v0 Host check is an M4 production-activation gate. Closing every embedded raw-writer path remains an M5 prerequisite. Neither gate is silently claimed by this integration branch.

Hosted graph execution is also a pre-M4 serving gate. Until graph claims have exact root admission, execution-descriptor, ownership, and stop routing, the non-serving Host fails closed before claim lookup or durable mutation.

Plan, Deep Research, Expert Team, and Daily Review are separate product/ownership decisions. They do not block extraction of the already validated foundations and domains.

Review principles

Each slice should:

  • present a complete, independently understandable domain boundary from the upstream base available at the time;
  • establish one clear authority boundary with explicit commit, retry, disconnect, Host-death, drain, and recovery behavior where applicable;
  • keep production entrypoints unchanged until M4/M5;
  • use real process/UDS/Store coverage where the behavior depends on those boundaries;
  • avoid compatibility layers for the unreleased experimental v0 protocol.

Related to #853. Tracks #1167.

简体中文

背景

这是 Runtime Host M3 的非生产集成分支,整体进度由 #1167 跟踪,架构方向来自 #853

它用于先验证跨领域 ownership、lifecycle、recovery 与多 Client 行为,再把实现提取成能够独立审查的上游 slice。这个 Draft 是参考与集成证据分支,预计不会作为一个整体合并。

集成证据

当前分支已经集成并验证:

  • 每个 root 只有一个权威 Runtime Host、全双工 Client session、有界 subscription 与 canonical Session continuity;
  • kind-bound Storage authority 与 production Headless root-kind boundary;
  • 保留的 Interactive 领域具有 Host-owned closed operation,包括 Interaction、Message、Task Ledger、策略/配置、Runtime Resource、native provider 与 Session lifecycle;
  • 可正常 settle operation 的 drain、fail-stop owner isolation、old-Epoch recovery,以及真实 graceful/SIGKILL successor journey;
  • embedded Runtime 在 M5 原子切换前仍是唯一 production Interactive owner。

该分支现在停止扩张 feature。后续变更只应是上游同步,或维持其集成证据价值所必需的修复。有界 shutdown foundation 已通过 #1355 独立合并,不能从本集成分支本身推断。

Slice 提取

每个 slice 都从当时最新的 main 提取,而不是把本分支当成一个合并单元:

  1. 全双工 connection session 与有界 outbound delivery(#1350)kind-bound Storage authority 与 Headless boundary(#1354)通过进程 fail-stop 实现有界 shutdown(#1355),以及 protocol/dispatcher 与 root-admission foundation(#1356)均已合并;
  2. Message authority foundation(#1357)Canonical Session projection / continuity(#1358)均已合并;
  3. Interaction authority(#1359)已 rebase 到当前 main、完整重验并转为 Ready;
  4. Runtime Policy authority(#1401)已作为独立 slice 合并:canonical contract、lease-bound CAS、redacted credential authority、typed Host operation 与 backend activation/invalidation;
  5. Artifact authority(#1503)当前为 Ready:canonical identity、atomic publication/recovery、exact retry、revision-pinned query、tombstone/purge 与 protected evidence;
  6. Task Ledger authority(#1504)当前为 Ready:经过 lease 认证的 canonical reader/writer、Runtime TaskLedgerStore port、有界且绑定 revision 的 Host query,以及保守 resume trust;
  7. pending-start root-execution cancellation 与 Hosted graph composition 保持为 feat(runtime-host): establish message authority foundation #1357 后明确的 follow-up slice,不把部分行为写成 Message authority 已完成的能力;
  8. 剩余 Session-core 依赖链继续经过 Interaction -> hosted execution -> automation / goal;边界完整且无真实依赖的 authority vertical 可以并行推进。

这是初始依赖图,不预先固定 PR 数量。领域完整度比单纯压小 diff 更重要。混合型集成提交会按 ownership 重新切分,而不是整颗 cherry-pick。独立 slice 直接以 Ready 发布;只有确实依赖未合并前置 PR 的 slice 才保持 Draft。

同版本 stale v0 Host 的识别属于 M4 production activation gate。关闭全部 embedded raw-writer 路径仍是 M5 前置条件。这个集成分支不会暗示自己已经关闭了这两个 gate。

Hosted graph execution 同样是 M4 serving 前置。在 graph claim 具备精确 root admission、execution descriptor、ownership 与 stop routing 前,non-serving Host 会在读取 claim 或持久化 mutation 前 fail closed。

Plan、Deep Research、Expert Team 与 Daily Review 是独立的产品/ownership 决策,不阻塞已经验证的基础与领域实现开始提取。

审查原则

每个 slice 应当:

  • 能够基于当时的上游基线提供完整、可独立理解的领域边界;
  • 建立一个清晰的 authority boundary,并在适用时明确 commit、retry、disconnect、Host death、drain 与 recovery 行为;
  • 在 M4/M5 前不改变 production entrypoint;
  • 对依赖真实进程、UDS 或 Store 边界的行为使用真实覆盖;
  • 不为尚未发布的实验 v0 协议增加兼容层。

关联 #853;跟踪 #1167

@M4n5ter
M4n5ter force-pushed the feat/runtime-host-m3 branch 2 times, most recently from 627bfb2 to 2524bc9 Compare July 18, 2026 11:07
@M4n5ter
M4n5ter force-pushed the feat/runtime-host-m3 branch 6 times, most recently from 6642420 to 879266f Compare July 21, 2026 01:19
@M4n5ter
M4n5ter force-pushed the feat/runtime-host-m3 branch 2 times, most recently from 39901fd to e7fa5b4 Compare July 22, 2026 13:28
@M4n5ter
M4n5ter force-pushed the feat/runtime-host-m3 branch from e7fa5b4 to daf7fd7 Compare July 22, 2026 14:15
@Astro-Han

Copy link
Copy Markdown
Contributor

I went through the seam surface of this branch (protocol specs, dispatcher, composition root, storage authority substrate) and ran the gate-related suites on it: protocol, host-kernel, execution-host, runtime-resource-execution-host, session-management-uds, and storage root-authority, all green. The registry pattern and the storage substrate are consistent enough to build slices on, and the tiered extraction plan in #1167 mostly holds. Three things need settling before extraction starts, plus one correction to the slice map.

1. Normal shutdown is not actually bounded (hard gate 3).

#closeResources waits with SHUTDOWN_OPERATION_GRACE_MS and destroys transports on expiry, but then awaits the same operation promises again with no deadline. #raceFailStop only races the fail-stop signal (host-kernel.ts:663, :984). A handler that never settles (hung store I/O, a native provider that died without answering, stuck resource startup in terminateAll) keeps the process alive and the owner lock held forever. SIGKILL recovery works because the OS reclaims the flock and the parked work dies with the process; the graceful path has no equivalent guarantee, and destroying the socket does not cancel the server-side handler.

A timeout alone does not fix this. Releasing the lock after a deadline while hung writes can still resume recreates the dual-write that gate 1 forbids. The missing piece is a written fail-stop contract: process exit as the death guarantee, with the OS reclaiming the flock, or isolating hangable I/O in killable workers. The RFC already treats the OS lock as the sole ownership authority, so formalizing "exit on deadline" stays closer to the design than waiting longer. This belongs in the foundations, since every domain coordinator copies its close/drain semantics from there.

2. v0 cannot detect a stale same-version Host.

The handshake compares only the integer 0 (host-kernel.ts:425). A client built with newer domain operations connects cleanly to an older v0 Host, the first unknown operation kills the connection (operations.ts:502, connection-session.ts:61), and connectOrSpawn never triggers replacement because the version matched. During extraction this mixed state is the norm on any dev machine. The replace-not-compat stance for v0 is right, but replacement needs a detection signal: a schema or build fingerprint in the handshake, or a rule that every spec change bumps the version. Worth deciding before slices land, since each slice changes the schema.

3. Slice map correction: the session core is a dependency chain, not flat verticals.

Walking the composition wiring: root-admission-owner -> message -> canonical projection -> continuity -> interaction -> root-turn -> {automation, goal}; oauth depends on native-provider; model composition needs native-provider for the browser and computer-use tools. The flat tier is therefore smaller than "13 domains". After foundations (storage authority, protocol/dispatcher skeleton, SessionAdmissionGate, root-admission-owner), the session-core cluster lands as one PR or a short stack. Then roughly nine verticals are genuinely flat: runtime-policy, memory, artifact, task-ledger, skill-catalog, usage-pricing, oauth, automation, goal. Session control plane stays last, which the fencing semantics force anyway. Same shape as the current plan, fewer flat lanes.

Smaller items that can ride with their slices:

  • retry/admission spec metadata has no consumer; each domain backs its own declaration by hand. Add response-loss replay contract tests per safe/semantic command, or mark the fields documentary before 13 slices replicate the pattern.
  • usage/pricing reads bypass the lease (usage-stores.ts:273); other authority facades reject revoked leases, this one still serves reads. Fix it or make the detached-snapshot semantics explicit.
  • The embedded Desktop writer still opens raw stores outside the lock protocol (apps/desktop/src/main/main.ts:202). Latent today, since nothing spawns a Host against production roots, but the M5 precondition "no Host spawn against a root with a live embedded writer" should be written down now, with the raw factories enumerated.
  • Gate test gaps: no real-process test for provider death after an admitted native effect (gate 4), no archive/remove raced against an active turn plus pending interaction plus automation fire (gate 6), no candidate-level refusal test for a headless-marked root (gate 5).
  • The require* late binding in execution-composition fails at recovery time if construction order shifts during slicing. A compose-time assertion resolving all refs would make reordering fail fast.

None of this challenges the architecture itself. Items 1 and 2 block extraction; the rest can ship with their slices.

简体中文

我过了一遍这个分支的接缝层(protocol spec、dispatcher、composition root、storage authority 基板),并在分支上跑了 gate 相关测试套件:protocol、host-kernel、execution-host、runtime-resource-execution-host、session-management-uds 与 storage root-authority,全部通过。注册表模式和 storage 基板足够一致,可以承载 slice 拆分;#1167 里的分层提取方案大体成立。有三件事需要在开始拆分前定下来,外加一处对切片地图的修正。

1. 正常 shutdown 实际上不是有界的(hard gate 3)。

#closeResources 先用 SHUTDOWN_OPERATION_GRACE_MS 等待、到期后销毁 transport,但随后又在同一批 operation Promise 上无超时等待。#raceFailStop 只 race fail-stop 信号(host-kernel.ts:663:984)。一个永不 settle 的 handler(挂死的 store I/O、死了但没回包的 native provider、卡在 terminateAll 里的 resource startup)会让进程一直活着,owner lock 永不释放。SIGKILL 恢复没问题,因为 OS 会回收 flock,悬着的工作随进程一起死;graceful 路径没有等价保证,销毁 socket 并不会取消 server 端的 handler。

光加 timeout 修不好。到期放锁、而挂起的写之后恢复,恰好重新制造 gate 1 禁止的双写。缺的是一份书面的 fail-stop 契约:以进程退出作为死亡保证、由 OS 回收 flock,或者把可能悬挂的 I/O 隔离进可强杀的 worker。RFC 已经把 OS 锁当作唯一 ownership 权威,所以把"到期退出"正式化比"继续等"更贴合原设计。这属于 foundations,因为每个领域 coordinator 的 close/drain 语义都从这里复制。

2. v0 无法识别同版本的过期 Host。

握手只比较整数 0(host-kernel.ts:425)。带着新 domain operation 构建的 client 能正常连上旧的 v0 Host,第一个未知 operation 会把连接打断(operations.ts:502connection-session.ts:61),而 connectOrSpawn 因为版本匹配不会触发 replacement。拆分期间,这种混版状态在任何开发机上都是常态。v0 走 replace 而非兼容的方向是对的,但 replace 需要检测手段:在握手里带 schema 或 build fingerprint,或者规定每次 spec 变更就 bump 版本。值得在切片落地前定,因为每个 slice 都会改 schema。

3. 切片地图修正:session core 是依赖链,不是 flat vertical。

沿 composition 接线走一遍:root-admission-owner -> message -> canonical projection -> continuity -> interaction -> root-turn -> {automation, goal};oauth 依赖 native-provider;model composition 需要 native-provider 提供 browser 和 computer-use 工具。因此真正 flat 的一层比"13 个领域"小。foundations(storage authority、protocol/dispatcher 骨架、SessionAdmissionGate、root-admission-owner)落地后,session-core 簇作为一个 PR 或一串短 stack 落地;之后大约九个 vertical 真正 flat:runtime-policy、memory、artifact、task-ledger、skill-catalog、usage-pricing、oauth、automation、goal。session control plane 仍在最后,fencing 语义本来就强制这一点。整体形状和现有方案一致,只是 flat 车道更少。

可以随各自 slice 携带的小项:

  • retry/admission spec 元数据没有消费者,各领域靠手写保证自己的声明。给每个 safe/semantic command 补 response-loss 重放契约测试,或在 13 个 slice 复制这个模式之前把字段明确标为 documentary。
  • usage/pricing 读侧绕过 lease(usage-stores.ts:273):其他 authority facade 在 lease 撤销后拒绝,它仍然提供读。修复,或把 detached-snapshot 语义写明。
  • embedded Desktop writer 仍在锁协议之外直接开裸 store(apps/desktop/src/main/main.ts:202)。当前是 latent,因为没有东西会对 production root 起 Host,但 M5 前提"有 live embedded writer 的 root 上不得 spawn Host"应该现在写下来,并枚举裸 factory 出口。
  • gate 测试缺口:gate 4 缺"已 admitted native effect 后 provider 进程死亡"的真实进程测试;gate 6 缺 archive/remove 与 active turn + pending interaction + automation fire 同时竞态的测试;gate 5 缺 headless-marked root 的 candidate 级拒绝测试。
  • execution-composition 里的 require* 晚绑定在切片导致构造顺序变化时,要到 recovery 期才暴露。加一个 compose 期解析所有引用的断言,让重排在构建期就失败。

这些都不动摇架构本身。第 1、2 项阻塞拆分,其余随各自 slice 携带即可。

@M4n5ter

M4n5ter commented Jul 22, 2026

Copy link
Copy Markdown
Member Author

@Astro-Han

English

Thanks for walking the branch at the seam level. I agree with most of the findings, with one adjustment to when item 2 becomes blocking.

1. Bounded shutdown

Agreed. Destroying transports does not bound server-side operations, and releasing the owner lock while a suspended write may resume would violate the single-writer invariant.

I think the foundation contract should be:

  • normal drain remains bounded;
  • once the deadline expires, the Host enters fail-stop and never releases ownership through normal cleanup;
  • process termination becomes the death guarantee, and the OS reclaims the owner lock.

We should settle this before extracting Host-owned domains that inherit the same close/drain lifecycle.

2. Stale same-version Host

The failure mode is real, but I would classify it as an M4 activation gate rather than a blocker for the current non-serving M3 extraction.

Before M4, no production Desktop/TUI/CLI surface launches or depends on a long-lived Runtime Host. Real-process tests use isolated roots and own their process cleanup. A stale v0 Host can currently arise in manual integration work, but it is a recoverable development-state failure rather than a production ownership risk.

Before the first production Client is enabled, the handshake must distinguish incompatible schema epochs, either through an explicit protocol epoch bump or a schema/build fingerprint. We should decide that before M4 rather than build a broader compatibility system during independent M3 slice extraction.

3. Slice topology

Agreed that the Session core is a dependency chain rather than a flat set of verticals. We will update the extraction map to represent it as one cohesive PR or a short stack:

root admission
→ message
→ canonical projection
→ continuity
→ interaction
→ root turn
→ automation / goal

A genuinely dependent PR can remain Draft until its prerequisite lands; independent authority slices can still be reviewed and merged directly.

Smaller items

  • retry / admission: resolve in the protocol/dispatcher foundation. If nothing consumes the metadata, it should be removed or explicitly non-normative rather than copied across domains.
  • usage/pricing: close the lease-bound read gap in its own authority slice, unless the API is deliberately changed to return detached snapshots.
  • Desktop raw writers: record their complete removal/closure as an explicit M5 precondition before any production Host can open the same root.
  • gate coverage: attach each real-process test to the slice that owns the behavior; add the headless-root Candidate refusal early, and defer the cross-domain archive/remove race until the Session core exists.
  • require* binding: add a compose-time resolution assertion before the Session-core stack starts moving construction order around.

I will reflect this dependency topology and gate placement in #1167. The current integration PR remains frozen as evidence; these corrections should be made in the extracted foundations and slices rather than by expanding #1190.

简体中文

感谢你从接缝层完整检查这条分支。大部分 finding 我都认同,但第 2 项成为阻塞项的时间点,我认为需要稍作调整。

1. 有界 shutdown

认同。销毁 transport 无法约束服务端 operation;如果挂起写入仍可能恢复,超时后主动释放 owner lock 也会破坏 single-writer 不变量。

我认为 foundation 契约应当是:

  • 正常 drain 保持有界;
  • deadline 到期后 Host 进入 fail-stop,不再通过正常清理主动释放 ownership;
  • 由进程终止提供死亡保证,并由 OS 回收 owner lock。

所有继承这套 close/drain lifecycle 的 Host-owned domain 在提取前都应先解决这一点。

2. 同版本 stale Host

这个 failure mode 确实存在,但我倾向于把它归类为 M4 activation gate,而不是当前 non-serving M3 slice 提取的 blocker。

M4 前没有 production Desktop/TUI/CLI surface 启动或依赖长期运行的 Runtime Host;真实进程测试使用隔离 root,并自行管理进程清理。目前 stale v0 Host 主要可能来自人工集成测试,属于可恢复的开发环境失败,而不是 production ownership 风险。

在启用第一个 production Client 前,握手必须能够区分不兼容的 schema epoch,可以直接 bump protocol epoch,也可以加入 schema/build fingerprint。我们应在 M4 前决定,而不必在独立 M3 slice 提取阶段提前建立更大的兼容系统。

3. Slice 拓扑

认同 Session core 是依赖链,而不是一组完全平铺的 vertical。我们会把提取图调整为一个完整 PR 或短 stack:

root admission
→ message
→ canonical projection
→ continuity
→ interaction
→ root turn
→ automation / goal

具有真实依赖的后续 PR 可以在前置合并前保持 Draft;独立 authority slice 仍可直接审查和合并。

其余小项

  • retry / admission:在 protocol/dispatcher foundation 中解决。若没有消费者,应删除或明确标记为非规范性信息,而不是复制到所有 domain。
  • usage/pricing:在对应 authority slice 中补齐 lease-bound read;除非 API 明确改为 detached snapshot。
  • Desktop raw writer:将完整关闭/删除列为 M5 的明确前置条件,production Host 在此之前不得打开同一 root。
  • gate coverage:真实测试随其所属 slice 落地;尽早补 Candidate 对 Headless root 的拒绝,跨领域 archive/remove race 等 Session core 完整后再做。
  • require* binding:在 Session-core stack 开始调整 construction order 前增加 compose-time resolution assertion。

我会把依赖拓扑和 gate 所属阶段反映到 #1167。当前集成 PR 继续冻结为集成证据,这些修正应落在提取出的 foundation 和各个 slice 中,而不是继续扩张 #1190

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants