Repository navigation
architecture(runtime-host): converge local Host lifecycle through owner-scoped reconciliation #3709
Description
English
Problem
Local Runtime Host lifecycle is split across two Draft PRs that discover different parts of the same owner transition:
| Draft | Problem it solves | Control path |
|---|---|---|
| #3706 | A connected compatible Desktop owner performs a full quit, but its durable-resident ephemeral Host survives and keeps the State Root writer | authenticated host.upgrade.prepare followed by exact-PID exit observation |
| #3254 | A newly installed local CLI/TUI cannot use the existing Host generation and needs Restart / Wait / Cancel handling | installation context, generation-aware handshake, and exact-epoch takeover |
Both drafts preserve important safety properties: exact Host Epoch fencing, local ownership checks, no registration/PID-only termination, remote/service isolation, and explicit user authority before destructive interruption. They also expose different design pressures.
#3706 design pressure
- Generic retirement is exposed through the historical
host.upgrade.preparewire operation. - Desktop Quit and Desktop Update share a retirement adapter, but concurrent requests coalesce onto the first policy. A later
interrupt_active_workrequest cannot strengthen an in-flightrefuse_active_workrequest. - The returned
resume()callback means “allow the owner lifecycle to create a successor after retirement,” not “resume the retired Host.”
#3254 design pressure
connectOrSpawncarries connection admission, candidate launch, generation inspection, and takeover policy.- TUI performs an additional exact-generation handshake to obtain replacement facts instead of calling an owner-side lifecycle inspection contract.
- A package path is a useful negative guard, but it is not positive proof of durable installation authority.
- Package version and generation labels are diagnostics, not verified immutable deployment identity.
- feat(cli): reconcile local Runtime Host generations #3254 records takeover of an epoch-24 Host with a
scheduled-taskresidency, while the current Host kernel's generation-takeover path requires#isTrueIdle(). Durable incompatible takeover is therefore legacy-dependent rather than a forward-compatible control contract. - Artifact staging, transition ownership, successor verification, and recovery remain outside one explicit local owner transaction.
The system needs one local lifecycle model without turning either connection election or the Runtime Host Kernel into a universal deployment authority.
Architectural foundation from #3228
#3228 establishes the layered model that local lifecycle work should reuse where the authority boundaries match:
- desired-state policy decides the exact state to converge toward and when reconciliation should run;
- explicit, idempotent owner transactions perform staging, retirement, cutover, verification, and recovery;
- the narrow Host retirement contract controls admission, active work, drain/interruption, and writer release;
- OS-service and local-process adapters apply those semantics through their respective authorities.
The managed-service path already provides exact-package deployment, side-by-side switching, current-operator handoff, process-lifetime locking, exact service/Host/Root fencing, readiness verification, and truthful retry recovery. #3687 adds verified npm integrity and binds selected current and target deployment identities to the update transaction. The remaining #3228 policy and scheduler work will add bounded and periodic desired-state reconciliation on top of those transactions.
Refs #3228
Refs #3231
Refs #3243
Refs #3245
Refs #3703
Desired outcome
Converge Desktop Quit, Desktop Update, installed CLI/TUI startup, and managed local ownership adapters on one layered, owner-scoped reconciliation model:
- one deployment owner has positive authority for each mutating transition;
- desired-state reconciliation remains above explicit idempotent owner transactions;
- every owner transaction consumes the same narrow Host retirement contract;
- capability and backend adapters remain bounded by observed Host and operator capabilities;
- Surface code collects intent and presents typed outcomes without owning lifecycle policy.
#3706 can land independently as the urgent exact-owner retirement slice. #3254 remains paused as compatibility and UX evidence while its replacement policy moves out of ordinary connection election. The #3228 policy, transaction, scheduling, and recovery boundaries are now stable through #3720 and the scheduler adapters in #3747. Draft PR #3766 is extracting only the shared verified deployment-identity contract before durable local ownership work begins.
Architecture principles
- One layered reconciliation model. Policy, owner transaction, Host retirement, and platform capability are separate layers with one-way authority flow.
- One owner per deployment. A mutation requires positive owner authority; an ordinary Client credential, package path, or successful connection is not deployment authority.
- One narrow Host retirement contract. Runtime Host Kernel remains the sole authority for admission, activity, drain, checkpoint/interruption, semantic recovery, and writer release.
- One explicit deployment identity.
DeploymentIdentitycarries source-appropriate verified evidence. Package version remains display and package-manager metadata. - One exact process fence. Every mutation against a present Host targets the observed
HostEpochand fails closed when identity or ownership changes. - Owner-scoped serialization. Process-lifetime owner locks serialize reconciliation and transactions. State Root writer ownership fences the actual cutover.
- Bounded capability adapters. Compatible retirement, legacy incompatible takeover, and operator control may use different mechanisms while preserving the same typed semantics and removal conditions.
- Thin Surface adapters. Desktop dialogs and TUI prompts collect consent and present outcomes; they do not select artifacts, own update journals, or implement replacement loops.
- Operator authority remains separate. Remote and local service-mode Hosts are mutated only through their operator; a connecting Desktop or TUI never acquires that authority.
Target contract
type DesiredOwnedHostState =
| { kind: 'stopped' }
| { kind: 'running'; deployment: DeploymentIdentity };
type OwnedHostObservation =
| { kind: 'absent' }
| { kind: 'present'; hostEpoch: HostEpoch };
type ActiveWorkPolicy =
| 'refuse'
| 'checkpoint_and_interrupt';
reconcileOwnedHost({
owner,
rootId,
observedHost,
desiredState,
activeWorkPolicy,
});stopped is owner-scoped: the Host owned by the identified owner has retired. It does not assert that the State Root must remain globally stopped or prohibit another authorized owner from starting a successor.
The reconciler determines a convergence plan and invokes explicit owner transactions:
- validate owner authority and serialize the owner transition;
- resolve an exact desired deployment when
runningis requested; - inspect the exact current Host through an observed capability adapter;
- stage the selected deployment before destructive mutation;
- return typed blockers when policy refuses active-work interruption;
- fence admission and request checkpoint/drain or explicit interruption;
- observe writer release rather than infer retirement from stale registration;
- stop at owner-scoped
stopped, or activate and launch the selected deployment; - verify successor Root, Host Epoch, deployment identity, and readiness;
- publish a typed terminal outcome sufficient for bounded retry and recovery.
The reconciler coordinates these transactions; it does not move deployment authority into the Host Kernel or replace explicit transaction recovery with an in-memory desired-state loop.
Serialization and ownership
A generic root-scoped transition lease is not a default requirement. It can serialize competing installations, but it cannot decide which installation is authorized and may preserve authority ambiguity instead of eliminating it.
The default model is:
- one durable deployment owner provides positive mutation authority;
- owner-scoped process-lifetime locks serialize its reconciliation and transactions;
- exact owner/Host/service identity checks prevent mutation of a successor or another operator's Host;
- the State Root writer fence protects the actual cutover.
A root-scoped transaction is introduced only for a supported ownership-transfer operation or another concrete path where multiple authorized owners must coordinate.
Deployment identity
Immutable deployment identity is partly delivered. #3687 uses verified npm SHA-512 integrity to distinguish registry artifacts, including same-version packages with different content, and binds the selected current and target deployment identities to the update transaction.
Draft PR #3766 is implementing this as a small shared DeploymentIdentity envelope carrying source-appropriate verified evidence. Deployment identity participates in running(exactDeployment) reconciliation but remains outside Host retirement. Ownership and lifecycle semantics for transient invocation sources are separate product decisions and are not prerequisites for #3703 or this architecture.
Product mappings
| Product action | Reconciliation | Policy |
|---|---|---|
| Desktop full Quit | owner-scoped stopped |
checkpoint_and_interrupt |
Close one Surface / TUI /exit |
no reconciliation; disconnect only | n/a |
| Desktop or installed CLI update | running(exactDeployment) |
refuse first; explicit interruption after confirmation |
| Installed CLI/TUI incompatible startup | running(exactDeployment) |
Restart / Wait / Cancel over typed owner facts |
| Remote or local service operation | operator-owned desired state | operator authority only |
| Unattended managed update | policy-selected exact deployment | bounded reconciliation through #3228 |
#3228 architecture gate
#3706 does not wait for #3228. The new local owner/reconciliation implementation waits only until these #3228 core contracts are stable:
- policy resolves to an exact desired deployment;
- bounded one-shot reconciliation delegates to the verified update transaction;
- scheduling reuses the same reconciliation entry point;
- retry and recovery outcomes form a stable machine contract.
Desktop update-policy UI or other remaining presentation work is not an architecture gate once those contracts are stable.
Convergence sequence
- fix(desktop): retire the owned local Host on full quit #3706 delivered the urgent exact-owner retirement path.
- Keep feat(cli): reconcile local Runtime Host generations #3254 paused while retaining its useful diagnostics and released-Host compatibility evidence.
- feat(runtime-host): add managed update reconciliation #3720 delivered the [Tracking] Managed remote Runtime Host onboarding and lifecycle #3228 reconciliation core; feat(runtime-host): schedule managed update reconciliation #3747 adds scheduler reuse, while Desktop issue feat(desktop): manage per-Host Runtime Host update policy #3768 is product presentation rather than an architecture gate.
- Land refactor(runtime-host): share verified deployment identity #3766 as the narrow shared verified deployment-identity contract.
- Define the durable local owner record, machine-readable owner transaction surface, and local-process adapter.
- Implement owner-scoped local reconciliation over the shared transaction model.
- Move replacement policy out of
connectOrSpawnand Surface-owned loops. - Retain bounded adapters for released Hosts and remove them when the stable owner control capability is broadly available.
AI-agent-assisted development keeps this architecture gate short and allows the resulting stack to land quickly without preserving transitional architecture for months. It does not require combining authority, protocol, deployment, recovery, and presentation changes into one oversized review unit.
Acceptance criteria
- Desktop full Quit retires its exact durable-resident owned ephemeral Host before exit or returns an actionable bounded failure.
stoppedis always interpreted within an explicit owner scope.- Installed CLI/TUI replacement policy is outside ordinary
connectOrSpawnadmission. - Desired-state policy, owner transactions, Host retirement, and capability adapters remain separate layers.
- Concurrent Quit/Update/Restart consent and policy escalation produce deterministic typed outcomes.
- Exact Host Epoch and State Root writer ownership are verified across retirement and successor startup.
- Durable schedules and continuation intent recover under the selected successor; unresolved external effects remain
result_unknown. - Remote and service-mode Hosts remain operator-owned.
- Failure outcomes include bounded Host facts and authenticated PID when available, without automatic PID-only termination.
- Released-Host compatibility adapters have explicit capability selection and removal conditions.
- [Tracking] Managed remote Runtime Host onboarding and lifecycle #3228 managed policy and local lifecycle reuse the same reconciliation concepts without forcing service-specific policy into local-process adapters.
Concepts to delete
host.upgrade.prepareas the public lifecycle semantic after its bounded legacy window;- replacement-policy fields on ordinary
connectOrSpawncalls; - Surface-owned restart and replacement loops;
- package paths or successful connections as positive proof of deployment authority;
- version, build, or generation labels used as substitutes for explicit protocol, epoch, or deployment identities;
- in-memory callbacks as authority for a transition that crosses process replacement.
Non-goals
- A universal Runtime Host-owned package or deployment state machine
- A global “State Root must remain stopped” desired state
- A generic root-scoped lease without a concrete ownership-transfer requirement
- Deciding ownership semantics for transient invocation products
- One atomic PR containing every authority, protocol, deployment, recovery, and presentation change
- Registration/PID-only process termination
- Stopping managed remote or local service-mode Hosts through ordinary Client authority
AI assistance disclosure
Codex assisted with architecture analysis and drafting. The proposal is based on #3228, #3231, #3687, the code and tests in #3706 and #3254, and the current Runtime Host retirement, takeover, service-management, and State Root ownership contracts.
简体中文
问题
本地 Runtime Host 生命周期被拆在两个 Draft PR 中;它们发现的是同一次 owner transition 的不同部分:
| Draft | 解决的问题 | 控制路径 |
|---|---|---|
| #3706 | 已连接且协议兼容的 Desktop owner 执行完整退出,但其具有 durable residency 的 ephemeral Host 继续存活并持有 State Root writer | 认证后的 host.upgrade.prepare,随后观察精确 PID 退出 |
| #3254 | 新安装的本地 CLI/TUI 无法使用现有 Host generation,需要处理 Restart / Wait / Cancel | installation context、generation-aware handshake 和绑定精确 epoch 的 takeover |
两个 Draft 都保留了重要的安全属性:精确 Host Epoch fencing、本地 ownership 检查、禁止只依据 registration/PID 终止进程、隔离 remote/service,以及破坏性中断前的明确用户授权。它们也暴露了不同的设计压力。
#3706 的设计压力
- 通用 retirement 通过历史命名的
host.upgrade.preparewire operation 暴露。 - Desktop Quit 与 Desktop Update 共享 retirement adapter,但并发请求采用第一个 policy;后到的
interrupt_active_work无法增强正在执行的refuse_active_work。 - 返回的
resume()表示“retirement 后允许 owner lifecycle 创建 successor”,并不是恢复已经退场的 Host。
#3254 的设计压力
connectOrSpawn同时承载 connection admission、candidate launch、generation inspection 和 takeover policy。- TUI 通过额外一次 exact-generation handshake 获取 replacement facts,而不是调用 owner-side lifecycle inspection contract。
- Package path 是有用的负向 guard,但不能正向证明 durable installation authority。
- Package version 与 generation label 是诊断信息,不是经过验证的 immutable deployment identity。
- feat(cli): reconcile local Runtime Host generations #3254 记录了 epoch 24 Host 仍有
scheduled-taskresidency 时的 takeover,而当前 Host kernel 的 generation-takeover 路径要求#isTrueIdle()。因此,不兼容 Host 的 durable takeover 依赖 legacy 行为,而不是 forward-compatible control contract。 - Artifact staging、transition ownership、successor verification 与 recovery 尚未归属一条明确的 local owner transaction。
系统需要一套本地生命周期模型,同时不能把 connection election 或 Runtime Host Kernel 变成万能 deployment authority。
#3228 提供的架构基础
#3228 建立了本地生命周期工作在 authority 边界一致时应复用的分层模型:
- desired-state policy 决定应收敛到哪个精确状态,以及何时执行 reconciliation;
- 显式、幂等的 owner transaction 负责 staging、retirement、cutover、verification 与 recovery;
- 窄小的 Host retirement contract 负责 admission、active work、drain/interruption 与 writer release;
- OS-service 与 local-process adapter 通过各自的 authority 应用这些语义。
Managed-service 路径已经提供 exact-package deployment、side-by-side switching、current-operator handoff、process-lifetime locking、精确 service/Host/Root fencing、readiness verification 与真实的 retry recovery。#3687 增加了经过验证的 npm integrity,并将选定的 current/target deployment identity 绑定到更新事务。#3228 剩余的 policy 与 scheduler 工作将在这些事务之上增加 bounded 与 periodic desired-state reconciliation。
关联 #3228
关联 #3231
关联 #3243
关联 #3245
关联 #3703
期望结果
让 Desktop Quit、Desktop Update、installed CLI/TUI startup 与 managed local ownership adapter 收敛到一套分层、owner-scoped reconciliation 模型:
- 每个 mutation transition 只有一个具有正向 authority 的 deployment owner;
- desired-state reconciliation 位于显式幂等 owner transaction 之上;
- 每条 owner transaction 消费同一套窄小的 Host retirement contract;
- capability 与 backend adapter 按观察到的 Host 和 operator capability 保持有界;
- Surface code 只收集意图并展示 typed outcome,不拥有 lifecycle policy。
#3706 可以作为紧急的 exact-owner retirement 切片独立合并。#3254 保持暂停并作为兼容性与 UX 证据,同时把 replacement policy 移出普通 connection election。#3228 的 policy、transaction、scheduling 与 recovery 边界现已通过 #3720 和 #3747 中的 scheduler adapter 稳定。Draft PR #3766 正在提取共享的 verified deployment-identity 契约,之后再开始 durable local ownership 工作。
架构原则
- 一套分层 reconciliation 模型。 Policy、owner transaction、Host retirement 与 platform capability 是 authority 单向流动的独立层。
- 每个 deployment 一个 owner。 Mutation 需要正向 owner authority;普通 Client credential、package path 或成功连接都不是 deployment authority。
- 一套窄小的 Host retirement contract。 Runtime Host Kernel 继续独占 admission、activity、drain、checkpoint/interruption、semantic recovery 与 writer release authority。
- 一种明确的 deployment identity。
DeploymentIdentity携带与来源匹配且经过验证的证据;package version 只负责展示与 package-manager metadata。 - 一道精确 process fence。 针对 present Host 的每次 mutation 都绑定 observed
HostEpoch,identity 或 ownership 改变时 fail closed。 - Owner-scoped serialization。 Process-lifetime owner lock 序列化 reconciliation 与 transaction;State Root writer ownership 保护实际 cutover。
- 有边界的 capability adapter。 Compatible retirement、legacy incompatible takeover 与 operator control 可以使用不同机制,但必须保持相同 typed semantic 和删除条件。
- 薄 Surface adapter。 Desktop dialog 与 TUI prompt 只收集 consent、展示 outcome,不选择 artifact、不拥有 update journal,也不实现 replacement loop。
- Operator authority 保持独立。 Remote 和 local service-mode Host 只能由 operator 执行 mutation;连接它们的 Desktop 或 TUI 不获得该 authority。
目标契约
type DesiredOwnedHostState =
| { kind: 'stopped' }
| { kind: 'running'; deployment: DeploymentIdentity };
type OwnedHostObservation =
| { kind: 'absent' }
| { kind: 'present'; hostEpoch: HostEpoch };
type ActiveWorkPolicy =
| 'refuse'
| 'checkpoint_and_interrupt';
reconcileOwnedHost({
owner,
rootId,
observedHost,
desiredState,
activeWorkPolicy,
});stopped 具有 owner 作用域:由指定 owner 拥有的 Host 已经退场。它不声明 State Root 必须全局保持停止,也不禁止另一个经过授权的 owner 启动 successor。
Reconciler 决定收敛计划并调用显式 owner transaction:
- 验证 owner authority 并序列化 owner transition;
- 请求
running时解析精确 desired deployment; - 通过观察到的 capability adapter 检查精确 current Host;
- 在破坏性 mutation 前 stage selected deployment;
- policy 拒绝中断 active work 时返回 typed blocker;
- fence admission,并请求 checkpoint/drain 或明确 interruption;
- 观察 writer release,而不是从 stale registration 推断 retirement;
- 在 owner-scoped
stopped结束,或 activate 并启动 selected deployment; - 验证 successor Root、Host Epoch、deployment identity 与 readiness;
- 发布足以支持有界 retry 和 recovery 的 typed terminal outcome。
Reconciler 负责协调这些事务;它不会把 deployment authority 移入 Host Kernel,也不会用内存 desired-state loop 取代显式 transaction recovery。
序列化与 ownership
通用 root-scoped transition lease 不是默认要求。它可以序列化相互竞争的 installation,却不能决定哪个 installation 有权操作,反而可能保留 authority 歧义。
默认模型是:
- 一个 durable deployment owner 提供正向 mutation authority;
- owner-scoped process-lifetime lock 序列化该 owner 的 reconciliation 与 transaction;
- 精确 owner/Host/service identity 检查防止 mutation 落到 successor 或其他 operator 的 Host;
- State Root writer fence 保护实际 cutover。
只有存在受支持的 ownership-transfer operation,或其他多个合法 owner 必须协调的具体路径时,才引入 root-scoped transaction。
Deployment identity
Immutable deployment identity 已经部分交付。#3687 使用经过验证的 npm SHA-512 integrity 区分 registry artifact,包括同版本不同内容的 package,并将选定的 current/target deployment identity 绑定到更新事务。
Draft PR #3766 正在将其实现为一个很薄的共享 DeploymentIdentity envelope,携带与来源匹配且经过验证的证据。Deployment identity 参与 running(exactDeployment) reconciliation,但仍位于 Host retirement 之外。临时 invocation 来源的 ownership 与生命周期语义属于独立产品决策,不是 #3703 或本架构的前置条件。
产品动作映射
| 产品动作 | Reconciliation | Policy |
|---|---|---|
| Desktop 完整退出 | owner-scoped stopped |
checkpoint_and_interrupt |
关闭一个 Surface / TUI /exit |
不执行 reconciliation,只 disconnect | 不适用 |
| Desktop 或 installed CLI update | running(exactDeployment) |
先 refuse;确认后显式 interruption |
| Installed CLI/TUI incompatible startup | running(exactDeployment) |
在 typed owner facts 上展示 Restart / Wait / Cancel |
| Remote 或 local service operation | operator-owned desired state | 仅 operator authority |
| Unattended managed update | policy 选择的精确 deployment | 通过 #3228 执行 bounded reconciliation |
#3228 architecture gate
#3706 不等待 #3228。新的本地 owner/reconciliation 实现只等待以下 #3228 核心契约稳定:
- policy 解析为精确 desired deployment;
- bounded one-shot reconciliation 委托给已经验证的 update transaction;
- scheduler 复用同一个 reconciliation 入口;
- retry 与 recovery outcome 形成稳定的机器契约。
这些契约稳定后,Desktop update-policy UI 或其他剩余 presentation 工作不再构成 architecture gate。
收敛顺序
- fix(desktop): retire the owned local Host on full quit #3706 已交付紧急的 exact-owner retirement 路径。
- feat(cli): reconcile local Runtime Host generations #3254 继续暂停,只保留有价值的诊断与 released-Host 兼容性证据。
- feat(runtime-host): add managed update reconciliation #3720 已交付 [Tracking] Managed remote Runtime Host onboarding and lifecycle #3228 reconciliation core;feat(runtime-host): schedule managed update reconciliation #3747 增加 scheduler 复用,而 Desktop issue feat(desktop): manage per-Host Runtime Host update policy #3768 属于产品展示,不是架构 gate。
- 以 refactor(runtime-host): share verified deployment identity #3766 交付窄小的共享 verified deployment-identity 契约。
- 定义 durable local owner record、机器可读 owner transaction surface 与 local-process adapter。
- 在共享 transaction model 上实现 owner-scoped local reconciliation。
- 将 replacement policy 移出
connectOrSpawn与 Surface-owned loop。 - 为已发布 Host 保留有界 adapter,并在稳定 owner control capability 广泛可用后删除。
AI agent 辅助开发使这个 architecture gate 保持短暂,并能在不让过渡架构存在数月的前提下快速交付整组实现。它不要求把 authority、protocol、deployment、recovery 与 presentation 变更合并成一个过大的评审单元。
验收标准
- Desktop 完整退出会在应用退出前让自己拥有且具有 durable residency 的精确 ephemeral Host 退场,或返回可操作的有界失败。
stopped始终在明确 owner 作用域内解释。- Installed CLI/TUI replacement policy 位于普通
connectOrSpawnadmission 之外。 - Desired-state policy、owner transaction、Host retirement 与 capability adapter 保持分层。
- 并发 Quit/Update/Restart 的 consent 与 policy escalation 产生确定的 typed outcome。
- Retirement 与 successor startup 全程验证精确 Host Epoch 和 State Root writer ownership。
- Durable schedule 与 continuation intent 在 selected successor 中恢复;无法确认的 external effect 保持
result_unknown。 - Remote 与 service-mode Host 保持 operator-owned。
- Failure outcome 包含有界 Host facts 和可获得时经认证的 PID,不执行 PID-only 自动终止。
- Released-Host compatibility adapter 具有明确 capability selection 与删除条件。
- [Tracking] Managed remote Runtime Host onboarding and lifecycle #3228 managed policy 与本地生命周期复用相同 reconciliation concept,同时不把 service-specific policy 强行放入 local-process adapter。
应删除的概念
- 有界 legacy window 结束后作为公共 lifecycle semantic 的
host.upgrade.prepare; - 普通
connectOrSpawn调用中的 replacement-policy 字段; - Surface-owned restart 与 replacement loop;
- 把 package path 或成功连接当作 deployment authority 的正向证明;
- 用 version、build 或 generation label 代替明确的 protocol、epoch 或 deployment identity;
- 用内存 callback 作为跨 process replacement transition 的 authority。
非目标
- Runtime Host 拥有的通用 package 或 deployment 状态机
- “State Root 必须全局保持停止”的 desired state
- 在没有具体 ownership-transfer 需求时引入通用 root-scoped lease
- 决定临时 invocation 产品的 ownership 语义
- 用一个原子 PR 包含全部 authority、protocol、deployment、recovery 与 presentation 变更
- Registration/PID-only process termination
- 通过普通 Client authority 停止 managed remote 或 local service-mode Host
AI 辅助声明
Codex 协助了架构分析与起草。该提案依据 #3228、#3231、#3687、#3706 与 #3254 的代码和测试,以及当前 Runtime Host retirement、takeover、service-management 与 State Root ownership 契约。
Activity
M4n5ter commentedon Aug 24, 2026
English
@Astro-Han @me2seeks, could you review this proposed architecture and share any different model or counterexample?
The main decision is whether #3706 and #3254 should remain separate incremental lifecycle paths, or stay paused as Drafts and be superseded by one PR built around a single local Host reconciler.
The most useful challenges would be around:
connectOrSpawn;ArtifactIdacross Desktop, installed CLI, development builds, andnpx;Please call out any ownership, compatibility, recovery, or migration constraint that would make the proposed target model incorrect.
简体中文
@Astro-Han @me2seeks,麻烦审视一下这个架构提案;如果有不同模型或反例,请直接指出。
核心决策是:#3706 与 #3254 应继续作为两条独立的增量生命周期路径,还是保持 Draft 暂停状态,由一个基于统一本地 Host reconciler 的 PR 取代。
最希望得到挑战的部分包括:
connectOrSpawn当前承载的 artifact selection、candidate launch 和 replacement policy 分离;npx应分别通过什么构成 installation-owner authority 和 immutableArtifactId;如果存在会推翻目标模型的 ownership、compatibility、recovery 或 migration 约束,请直接指出。
me2seeks commentedon Aug 24, 2026
English
Thanks for the ping. I agree with the target direction—one local lifecycle owner and one owner-side reconciliation interface—but I do not think one replacement PR is the right atomic delivery unit.
I see three constraints:
1. One semantic reconciler still needs multiple capability adapters
Current
mainhas materially different Host control paths:host.upgrade.prepareoperation;hello, before Domain admission, and currentmainpermits it only when the Host is truly idle;A future lifecycle control plane independent of the Domain compatibility epoch is a good target, but it is currently Planned and cannot be retrofitted into already released Hosts. I would therefore keep one reconciler interface while selecting a bounded adapter from observed Host capabilities. “One lifecycle model” should not imply one wire mechanism across all historical epochs.
2. The serialization authority is not yet fully identified
A lock scoped to one installation/profile and State Root does not serialize two different local installations—such as Desktop and a globally installed CLI—targeting the same Root. The State Root writer and
HostEpochremain the authoritative fence, but #3709 should decide whether an additional root-scoped transition lease is required and which installation is authorized to acquire it. A package path or ordinary local credential is not sufficient positive proof of destructive installation-owner authority.3.
ArtifactIdis important, but it is a separate deployment contractI agree that package version and the current generation string are not immutable artifact identity. However, a verified
ArtifactIdmust define the runnable closure and provenance across Electron, installed CLI, development builds, andnpx. Desktop Quit only requestsstoppedand does not require artifact selection. Coupling this packaging decision to the urgent #3703 fix would unnecessarily block the availability repair.My preferred migration is:
connectOrSpawn;This gives us one lasting authority and interface without requiring every migration concern to land in one large PR. Would you be open to framing #3709 as the target architecture plus an explicit convergence sequence, rather than requiring one atomic replacement PR?
简体中文
感谢邀请。我认同目标方向——一个本地 lifecycle owner,以及一个 owner-side reconciliation interface——但我不认为用一个 PR 一次性取代现有实现,是合适的原子交付边界。
我看到三个约束:
1. 一个语义 reconciler 仍然需要多个 capability adapter
当前
main中存在实质不同的 Host 控制路径:host.upgrade.prepareoperation;hello阶段、Domain admission 之前,并且当前main只允许真正 idle 的 Host 被接管;独立于 Domain compatibility epoch 的 lifecycle control plane 是合理的未来目标,但它目前属于 Planned,也无法被追溯加入已经发布的旧 Host。因此,我倾向于保留一个 reconciler interface,再根据观察到的 Host capability 选择有界 adapter。“一个 lifecycle model”不应意味着所有历史 epoch 都必须使用同一种 wire mechanism。
2. 串行化 authority 尚未完全确定
仅按 installation/profile 与 State Root 加锁,无法串行化两个不同本地 installation——例如 Desktop 与全局安装的 CLI——同时针对同一个 Root 发起的 transition。State Root writer 与
HostEpoch仍应是权威 fence,但 #3709 还需要决定:是否需要额外的 root-scoped transition lease,以及哪个 installation 有权获取它。Package path 或普通 local credential 都不足以正向证明具有破坏性的 installation-owner authority。3.
ArtifactId很重要,但它属于独立的 deployment contract我同意 package version 和当前 generation string 都不是 immutable artifact identity。但经过验证的
ArtifactId必须定义 Electron、installed CLI、development build 与npx下的 runnable closure 和 provenance。Desktop Quit 只请求stopped,不需要 artifact selection。把这个 packaging 决策与紧急的 #3703 修复绑定,会不必要地阻塞启动可用性修复。我倾向的迁移顺序是:
connectOrSpawn中移出;这样可以得到一个长期 authority 和 interface,同时不要求所有迁移问题都塞进一个大型 PR。是否可以把 #3709 定义为目标架构与明确的收敛顺序,而不是要求一个原子化 replacement PR?
M4n5ter commentedon Aug 24, 2026
English
Thanks — I agree that #3709 should define the target architecture and an explicit convergence sequence rather than require one atomic replacement PR.
#3228 provides the architectural foundation for that sequence. Its completed and planned work forms a layered reconciliation model:
The completed managed-service work already provides exact-package deployment, side-by-side switching, current-operator handoff, process-lifetime locking, exact identity fencing, readiness verification, and truthful retry recovery. The remaining
manual | fixed | latest | nextpolicy and scheduler work will add bounded and periodic desired-state reconciliation on top of those transactions.Reconciliation boundary
A shared reconciliation model remains the correct target, but reconciliation must be owner-scoped:
stoppedmeans that the Host owned by the identified owner has been retired. It does not mean that the State Root must remain globally stopped or that another authorized owner can never start a successor.The reconciler determines the convergence plan and invokes explicit owner transactions. It does not replace those transactions or move their authority into the Host Kernel.
Shared retirement contract
The lasting Runtime primitive should remain narrow:
HostEpoch;Compatible operations, incompatible legacy takeover, and managed-service control may require different bounded capability adapters. They should converge on the same retirement semantics without assuming that every released Host exposes the same wire mechanism.
Serialization and authority
A root-scoped transition lease should not be assumed as the default solution.
The first requirement is one durable deployment owner with positive authority. Owner-scoped process-lifetime locks can serialize that owner's reconciliation and transactions, while exact identity checks and the State Root writer fence protect the actual cutover.
A generic root lease would serialize competing installations but would not determine which installation is authorized. It could preserve authority ambiguity instead of eliminating it.
A root-scoped transaction is justified only if the product defines an explicit ownership-transfer operation or another supported path where multiple authorized owners must coordinate. The ownership model should be established first.
Deployment identity
Immutable deployment identity is not entirely future work. #3687 already uses verified npm SHA-512 integrity to distinguish registry artifacts, including same-version packages with different content, and binds the selected current and target deployment identities to the update transaction.
The remaining contract should be a small
DeploymentIdentityenvelope carrying source-appropriate verified evidence. Ownership and lifecycle semantics for transient invocation sources remain separate product decisions and are not prerequisites for #3703 or this convergence.Deployment identity remains an installation/deployment concern. It should participate in
running(exactDeployment)reconciliation without becoming part of Host retirement or blocking Desktop Quit.Delivery decision
host.upgrade.preparewire mapping is transitional. Policy escalation for concurrent Update/Quit requests should be improved, but the current behavior is fail-closed and recoverable, so it is not a merge-blocking safety defect.connectOrSpawn. Handshake takeover should be a bounded capability adapter selected by the owner-side reconciler, not the installation-owner architecture itself.This is a narrow architecture gate, not a dependency on every remaining #3228 product surface. Local implementation can begin once the following contracts are stable:
A practical convergence sequence is therefore:
AI-agent-assisted development makes this short design gate inexpensive and allows the resulting stack to be implemented quickly. It does not justify freezing a parallel abstraction immediately before the reference reconciliation model is complete, nor does it require combining distinct authority, protocol, deployment, and recovery changes into one oversized review unit.
So yes: #3709 should become the target architecture plus convergence sequence. The target should be one layered reconciliation model, one owner per deployment, explicit idempotent owner transactions, one narrow Host retirement contract, and bounded capability adapters.
简体中文
感谢这个挑战。我同意 #3709 应定义目标架构和明确的收敛顺序,而不是要求一个原子化的 replacement PR。
#3228 为这条收敛路径提供了架构基础。它已经完成和仍在规划的工作共同构成了一套分层 reconciliation 模型:
已经完成的 managed-service 工作提供了 exact-package deployment、side-by-side switching、current-operator handoff、process-lifetime locking、精确 identity fencing、readiness verification 与真实的 retry recovery。剩余的
manual | fixed | latest | nextpolicy 和 scheduler 将在这些事务之上增加 bounded 与 periodic desired-state reconciliation。Reconciliation 边界
共享 reconciliation model 仍然是正确目标,但 reconciliation 必须限定在 owner 作用域内:
stopped表示由指定 owner 拥有的 Host 已经退场。它不表示 State Root 必须全局保持停止,也不表示另一个经过授权的 owner 永远不能启动 successor。Reconciler 负责决定收敛计划并调用显式 owner transaction。它不会取代这些事务,也不会把事务 authority 移入 Host Kernel。
共享 retirement contract
长期稳定的 Runtime primitive 应保持窄小:
HostEpoch;兼容 operation、不兼容 legacy takeover 与 managed-service control 可能需要不同的有界 capability adapter。它们应收敛到相同 retirement 语义,但不应假设所有已发布 Host 都提供同一种 wire mechanism。
序列化与 authority
不应预设必须增加通用的 root-scoped transition lease。
首要条件是建立一个具有正向授权的 durable deployment owner。Owner-scoped process-lifetime lock 可以序列化该 owner 的 reconciliation 与 transaction,精确 identity 检查和 State Root writer fence 则保护实际 cutover。
通用 root lease 只能序列化相互竞争的 installation,却不能决定哪个 installation 有权操作;它可能保留 authority 歧义,而不是消除它。
只有产品定义了显式 ownership transfer,或者存在其他多个合法 owner 必须协调的受支持路径时,root-scoped transaction 才有引入依据。应先确定 ownership model。
Deployment identity
Immutable deployment identity 并非完全属于未来工作。#3687 已使用经过验证的 npm SHA-512 integrity 区分 registry artifact,包括同版本不同内容的 package,并将选定的 current/target deployment identity 绑定到更新事务。
剩余契约应当是一个很薄的
DeploymentIdentityenvelope,携带与来源匹配且经过验证的证据。临时 invocation 来源的 ownership 与生命周期语义仍属于独立的产品决策,不是 #3703 或本次收敛的前置条件。Deployment identity 仍是 installation/deployment concern。它应参与
running(exactDeployment)reconciliation,但不能成为 Host retirement 的组成部分,也不应阻塞 Desktop Quit。交付决策
host.upgrade.preparewire mapping 属于过渡实现。并发 Update/Quit 的 policy escalation 应当改进,但当前行为是 fail-closed 且可恢复的,因此不构成阻塞合并的安全缺陷。connectOrSpawn。Handshake takeover 应成为由 owner-side reconciler 选择的有界 capability adapter,而不是 installation-owner 架构本身。这是一个范围明确的 architecture gate,并不要求等待 #3228 的所有产品界面。以下契约稳定后即可开始本地实现:
因此,实际收敛顺序是:
AI agent 辅助开发使这个短期 design gate 的成本很低,并能在边界稳定后快速完成整组实现。没有必要在参考 reconciliation model 即将完成前冻结一套平行抽象,也没有必要把不同的 authority、protocol、deployment 与 recovery 变更合并成一个过大的评审单元。
因此,#3709 应调整为目标架构与收敛顺序。真正的目标是:一套分层 reconciliation 模型、每个 deployment 一个 owner、显式幂等的 owner transaction、一套窄小的 Host retirement contract,以及有边界的 capability adapter。
[-]architecture(runtime-host): unify local Host reconciliation across quit, update, and incompatible startup[/-][+]architecture(runtime-host): converge local Host lifecycle through owner-scoped reconciliation[/+]me2seeks commentedon Aug 24, 2026
感谢澄清。我核对了 #3228 与 #3687,认同先让 #3706 作为窄小的 exact-owner retirement 修复落地、继续暂停 #3254,并等待 #3228 的 reconciliation core 稳定后再冻结 local contract。
Remote Host 的更新边界可以进一步表述为:普通 remote Client 与 compatibility failure 不会自动升级或重启 Host;更新由 deployment owner 根据用户选择的 policy 执行,默认
manual,用户也可以显式选择未来的fixed | latest | next无人值守策略。我也同意 root-scoped lease 本身不能证明 authority。剩余需要在 local implementation 前闭合的问题是 durable local owner 的正向来源与 transfer protocol:Desktop、全局 CLI、development build 与显式
npx ... runtime-host setup分别如何取得、拒绝或转移 ownership;尤其不能让临时 invocation 自动成为 owner,也不能阻止用户主动执行 setup。Root-scoped coordination 只应在明确存在多个合法 owner 或 ownership transfer 时引入。#3687 当前仍在评审中,因此我会把其中的
DeploymentIdentity视为正在形成的 reference contract,而不是已经进入 main 的 Current 事实。me2seeks commentedon Aug 24, 2026
English
Concrete local owner and transfer contract
The next local design slice can proceed without waiting for #3687 or #3720 because its question is independent of registry/update implementation: what durable fact authorizes one installation to mutate the local Host deployment for one State Root?
Verified current baseline
Current
HostRegistrationpublishesrootId,hostEpoch, compatibility/protocol facts, lifecycle mode, optional generation, and PID. It does not publish a deployment owner._npx” as replacement eligibility and package version/development UUID as generation. Those are useful negative guards and diagnostics, not positive durable-owner or verified-deployment evidence.Planned minimum record
The durable authority should be one machine-account-local record per
rootId; that single record identifies the current local deployment slot and owner. It must live in a persistent private authority namespace—not in the State Root payload, the cache-based Runtime Host control directory, an npm package path, or one Surface's memory.The exact JSON encoding is not the decision. The minimum semantic shape is:
HostEpoch, PID, package path, version, and compatibility epoch are deliberately absent from durable owner identity. They are observations/fences used by one transaction and must be re-observed after a crash.DeploymentIdentitycarries source-appropriate verified runnable-closure evidence; version remains display/package-manager metadata.The authority namespace is private to the OS account. This contract prevents accidental competing installations and stale operations; it does not claim cryptographic isolation from another malicious process running as the same OS user. Different OS accounts or machines sharing storage remain outside the active-active guarantee and still fail closed at the State Root writer lease.
Claim and transfer rules
npx ... runtime-host setup_npx—becomes ownernpx maka“Verified persistent” must mean the runnable closure has a source-appropriate
DeploymentIdentity. Merely being outside_npx, having a stable path, or reporting a version is insufficient.State transitions
ownedunder the authority lock using create-if-absent/CAS. A loser re-reads; it does not overwrite.owner_transfer_requiredwith bounded owner/deployment facts. Do not infer consent from package installation or successful connection.owned(to).transferringstate is recovered by re-observing the owner record, actual Host, writer lease, and artifacts. It never continues from a persisted PID orHostEpoch. Before durable transfer intent, the old owner remains authoritative; after it, neither installation may start an unrelated writer outside the transaction.One authority lock is enough. The State Root writer lock remains the cutover fence; it must not also become the source of deployment authorization. A root-scoped coordination lock is justified here only because explicit ownership transfer is a supported transaction.
Concrete examples
Desktop owns Root R; a new global CLI is compatible. The CLI connects and leaves the owner record unchanged. Same-epoch build skew is not a replacement request.
Desktop owns Root R; a new CLI is incompatible. The CLI shows
owner_transfer_requiredplus Restart/Wait/Cancel facts. Restart begins only after explicit consent and CAS of the Desktop owner revision. An epoch mismatch alone cannot authorize takeover.Direct
npx makastarts with no Host and no durable owner record. It may start an invocation-owned, non-durable Host without writing the durable owner record. If a durable owner record already exists but its Host is absent,npxmust not occupy that owner's slot; it connects to an owner-started Host or returns owner guidance. An invocation-owned Host is supervised by an invocation-liveness adapter and retires when that invocation ends. A foreground supervisor or inherited liveness handle is required; a detached process plus parent PID polling is not a sufficient cross-platform contract. Durable background work is unavailable without a persistent owner.The user runs
npx ... runtime-host setup. This is a different explicit intent. Setup verifies the invoked release, copies it to a Maka-managed persistent deployment, then installs systemd/LaunchAgent from that path. The service/managed deployment becomes owner; the_npxcache is never its executable or owner identity.The active owner executable disappears. The record is not silently stolen. A verified installation reports an orphaned owner and offers explicit recovery/transfer. The transaction re-observes the Host and artifacts and preserves the State Root; “last launcher wins” remains forbidden.
A remote Client sees a different epoch. It reports operator guidance only. The deployment owner on the Host machine applies
manualor an explicitly selected managed policy. No local owner record or ordinary remote credential updates that Host.Qualification and counterexample matrix
The contract is not ready until these cases have deterministic typed outcomes. Released-package tests should be used where historical behavior matters.
owner_changed; no Host is retiredHostEpochfails closed; transaction re-observesresult_unknownsemanticsnpxexits normallynpxis killed/crashes_npxcache is deleted while invocation runsnpx setupthen cache deletiontransferringrecovery re-observes writer/artifacts and completes or reports degraded state truthfullyowned(selected); previous verified artifact is retained where storage compatibility permitsConsequence for #3254
#3254 should remain paused, but it is not disposable as a whole. Its exact-epoch fencing, released-Host takeover probes, remote isolation, Restart/Wait/Cancel presentation, same-epoch compatibility evidence, and PTY scenarios should migrate into the eventual owner/reconciler stack. Its authority inference (
persistent != _npx), version-derived generation, and replacement requests carried by ordinaryconnectOrSpawnshould not.This closes the owner-rule product decision without freezing a large implementation: one durable record, one CAS/transition authority, one exact deployment identity, one Host writer fence, and bounded adapters.
Evidence was rechecked against current
main(2265b6bb9):packages/runtime-host/src/protocol/index.ts,packages/storage/src/root-authority.ts,packages/cli/src/runtime-host-service-manager.ts,apps/desktop/src/main/runtime-host-desktop-manager.ts, and the implementation/tests on Draft #3254.简体中文
具体的本地 owner 与 transfer 契约
下一项本地设计工作不必等待 #3687 或 #3720,因为它回答的是一个独立问题:哪个持久事实授权某个 installation 修改某个 State Root 对应的本地 Host deployment?
已核实的当前基线
Current
HostRegistration发布rootId、hostEpoch、compatibility/protocol、lifecycle mode、可选 generation 与 PID,但不发布 deployment owner。_npx”近似为 replacement eligibility,并把 package version/development UUID 近似为 generation。这些是有用的负向 guard 与诊断,不是正向 durable-owner 或 verified-deployment 证据。Planned 最小记录
每个 machine-account-local
rootId只有一份 durable authority record;由这份唯一记录指出当前 local deployment slot 与 owner。它必须位于持久、私有的 authority namespace;不能放进 State Root 数据、cache-based Runtime Host control directory、npm package path 或某个 Surface 的内存。具体 JSON 编码不是本次决定。最小语义结构是:
Durable owner identity 有意不包含
HostEpoch、PID、package path、version 与 compatibility epoch。它们只是单次 transaction 使用的 observation/fence,crash 后必须重新观察。DeploymentIdentity携带与来源匹配、经过验证的 runnable closure 证据;version 仍只是展示与 package-manager metadata。Authority namespace 对 OS account 私有。该契约防止同一账户下 installation 的误竞争与 stale operation,不宣称能以密码学方式隔离同一 OS 用户运行的恶意进程。不同 OS account 或机器共享 storage 不属于 active-active guarantee,最终仍由 State Root writer lease fail closed。
Claim 与 transfer 规则
npx ... runtime-host setup_npxnpx maka“Verified persistent”必须表示 runnable closure 已拥有来源匹配的
DeploymentIdentity。仅仅不位于_npx、路径稳定或能报告 version 都不够。状态转换
owned。竞争失败者重新读取,不覆盖。owner_transfer_required。不能从 package 安装或成功连接推断 consent。owned(to)。transferring状态通过重新观察 owner record、实际 Host、writer lease 与 artifact 恢复;绝不从持久 PID 或HostEpoch续跑。Transfer intent 持久化前,旧 owner 仍有 authority;持久化后,两边都不能绕开 transaction 启动无关 writer。只需要一把 authority lock。State Root writer lock 继续作为 cutover fence,不能同时充当 deployment authorization 来源。只有因为显式 ownership transfer 是受支持 transaction,root-scoped coordination lock 才有引入理由。
具体示例
Desktop 拥有 Root R,新 global CLI 与其兼容。 CLI 直接连接,owner record 不变;same-epoch build skew 不构成 replacement request。
Desktop 拥有 Root R,新 CLI 与其不兼容。 CLI 展示
owner_transfer_required与 Restart/Wait/Cancel facts。只有用户明确同意且 Desktop owner revision CAS 成功后才能 Restart;epoch mismatch 本身不授权 takeover。Direct
npx maka启动时既没有 Host,也没有 durable owner record。 它可以启动 invocation-owned、non-durable Host,但不写 durable owner record。如果 durable owner record 已存在而 Host 暂时不在,npx不能占用该 owner 的 slot;它只能连接 owner 启动的 Host,或返回 owner guidance。Invocation-owned Host 由 invocation-liveness adapter 监督,并随 invocation 结束而 retirement。必须使用 foreground supervisor 或 inherited liveness handle;detached process 加 parent PID polling 不是充分的跨平台契约。没有 persistent owner 时不提供 durable background work。用户运行
npx ... runtime-host setup。 这是另一种显式意图。Setup 验证本次 release,复制到 Maka-managed persistent deployment,再从该路径安装 systemd/LaunchAgent。Owner 是 service/managed deployment;_npxcache 永远不是 executable 或 owner identity。Active owner executable 消失。 Record 不会被静默抢占。另一个 verified installation 报告 orphaned owner,并提供显式 recovery/transfer。Transaction 重新观察 Host/artifact 并保留 State Root;继续禁止 last-launch-wins。
Remote Client 观察到不同 epoch。 它只报告 operator guidance。Host 机器上的 deployment owner 根据
manual或显式选择的 managed policy 操作;本地 owner record 和普通 remote credential 都不能更新该 Host。Qualification 与反例矩阵
在以下场景都有确定 typed outcome 前,契约不能视为 Ready。涉及历史行为时必须使用 released package 测试。
owner_changed;不 retirement HostHostEpochfail closed,并重新观察result_unknown语义npx正常退出npx被 kill/crash_npxcache 被删除npx setup后删除 cachetransferringrecovery 重验 writer/artifact,并完成或真实报告 degraded stateowned(selected);storage compatibility 允许时保留 previous verified artifact对 #3254 的影响
#3254 应继续暂停,但不是整份丢弃。Exact-epoch fencing、released-Host takeover probe、remote isolation、Restart/Wait/Cancel presentation、same-epoch compatibility evidence 与 PTY 场景应迁移到未来 owner/reconciler stack。Authority inference(
persistent != _npx)、version-derived generation,以及由普通connectOrSpawn携带 replacement request 的设计不应迁移。这项决定不冻结大型实现,只固定最小模型:一份 durable record、一套 CAS/transition authority、一种 exact deployment identity、一道 Host writer fence,以及有界 adapter。
证据已对照当前
main(2265b6bb9)重新核实:packages/runtime-host/src/protocol/index.ts、packages/storage/src/root-authority.ts、packages/cli/src/runtime-host-service-manager.ts、apps/desktop/src/main/runtime-host-desktop-manager.ts,以及 Draft #3254 的实现与测试。me2seeks commentedon Aug 25, 2026
English
Local owner implementation update
I split the first implementation step into two dependency-ordered PRs:
rootId, one authority lock, opaque revision CAS, and explicitowned/transferringtransitions.The split follows the authority boundary rather than file size: deployment evidence can stand alone and remain behavior-preserving; owner state, locking, transition semantics, persistence, and cross-process race tests remain together because separating them would create a partially authoritative record.
The owner PR deliberately does not:
HostEpoch;npxor an ordinary remote Client create durable ownership;Only the currently verified npm identity is accepted. Source-specific Desktop/development identities should be added with the adapter that can actually produce and verify that evidence. Remote and service-mode mutation remains operator-owned.
#3231 now tracks both PRs and records #3747 as a separate scheduler slice rather than a local-owner gate. #3254 remains paused as compatibility and UX evidence.
中文摘要
Local owner 实现进展
第一步已按依赖顺序拆成两个 PR:
rootId定义一份 OS 账户本地 owner record、一把 authority lock、opaque revision CAS,以及明确的owned/transferringtransition。拆分依据是 authority 边界,不是文件数量。Deployment evidence 可以独立且保持行为不变;owner state、locking、transition、persistence 与跨进程竞争测试必须放在一起,否则会产生只有部分权威性的记录。
Owner PR 不会从 package path、compatibility、version、PID 或
HostEpoch推断 authority;directnpx与普通 remote Client 不能创建 durable ownership;也不提前猜测 Desktop/development 的 artifact evidence,不执行 Host retirement、successor launch 或任何 Surface/operator adapter。当前只接受已经能够验证的 npm identity。Desktop/development 的来源证据应由真正能够生成并验证该证据的后续 adapter PR 定义。Remote 与 service-mode mutation 继续由 operator 拥有。
#3231 已追踪两个 PR,并将 #3747 记录为独立 scheduler 切片而不是 local-owner gate;#3254 继续暂停并保留为 compatibility/UX 证据。
Generated-by: Codex
me2seeks commentedon Aug 25, 2026
English
Local-process transfer transaction: Draft #3769
Draft #3769 implements the next dependency-ordered owner slice on top of #3767.
The shared transaction now enforces this sequence under the one owner-authority lock:
transferring;owned.Crash recovery never resumes a persisted PID or
HostEpoch. If a prior attempt already started the exact transaction-scoped target, recovery verifies that target and commits without retiring or launching it again. Failures after retirement preservetransferring; only anactive_workrefusal that guarantees retirement never began may restore the previous owner automatically.The transaction extends #3767 to hold the same authority lock across the complete cutover rather than acquiring another coordination lock. The State Root writer remains the final single-writer fence, not deployment authorization.
Two requested audits were applied before publication:
target_absentobservation.The adapter boundary is intentionally still explicit:
npx makacannot call this durable-owner path; explicitnpx ... runtime-host setupmay stage a managed persistent deployment, whose managed installation—not_npx—participates as owner.Draft #3769 currently includes #3766 and #3767 in the GitHub diff because an upstream PR cannot use a fork-only branch as its base. After those dependencies merge, it will be rebased onto
mainand retain only the transaction commit.Verification: the complete
@maka/runtime-hostsuite passes (1160/1160), including focused staging, stale confirmation, active-work rollback, post-retirement recovery, already-running target recovery, idempotent retry, and whole-cutover serialization cases.中文摘要
Local-process transfer transaction:Draft #3769
#3769 在 #3767 之上实现下一层 owner transaction:先 stage 并验证精确 target,再用同一把 owner-authority lock 完成 revision CAS、持久化
transferring、重新观察并 retire 旧 Host、确认 State Root writer 释放、启动并验证精确 target Ready,最后 commit 新 owner。Crash recovery 不持久化或复用 PID/
HostEpoch。如果上一次尝试已经启动本 transaction 的精确 target,恢复只重验并 commit,不会重复 retirement/launch。Retirement 之后失败会保留transferring;只有 active work 明确拒绝且保证 retirement 未开始时,才安全恢复旧 owner。双重审计后的最小方案只保留 durable transfer intent、一把 owner lock、现有 writer fence 与 source-specific capability;删除了无意义的“旧 Host 已退场/Host 原本不存在”双表示,没有增加第二份 deployment journal、daemon、remote mutation 或 version/epoch authority。
Desktop/installed CLI 可以使用 transaction-scoped launch fence;systemd/LaunchAgent 必须先 quiesce supervisor,并用 operator-owned managed deployment evidence 验证 target。Direct
npx maka不能走 durable owner transfer;显式npx ... runtime-host setup的 owner 是最终 managed installation,不是_npx。Remote Client 不能执行本地 owner transfer,remote Host 仍由 Host 机器上的 deployment operator 主动更新。#3769 因 GitHub 不能把 fork-only branch 作为上游 PR base,当前 diff 暂时包含 #3766/#3767;依赖合并后会 rebase 到
main,只保留 transaction commit。完整
@maka/runtime-host测试通过:1160/1160。Generated-by: Codex
Astro-Han commentedon Sep 4, 2026
We were tracing a user-reported quit failure and ended up reading through this area. Three findings that touch this issue, plus one question that doesn't.
1. #3706 fixed a symptom, and the root cause is still there.
The reason an owned Host survived a full quit wasn't a missing synchronous retirement — it's that
RuntimeHostDesktopManager.#close()unconditionally callscandidateLaunchBarrier?.release(). That barrier is also what detaches the launch-owner guard, so closing the manager tells the guard "this process is no longer the launcher" at the same moment it means "we're going away". The guard then ignores the IPC disconnect that would otherwise have closed the Host.This is the same conflation your
resume()note points at, on the Desktop side. If the guard's disconnect path is left intact, the Host closes on its own and the quit path does not need to drive retirement at all — which would remove the PID polling step 7 is trying to replace.2. One operation, two independent budgets. (corrected — see the note below)
The Host arms its shutdown deadline inside
#requestDrain()whilehost.upgrade.prepareis still being handled; Desktop'swaitForProcessExitdeadline starts only after the response arrives. Two hardcoded constants, in different packages, describing one operation, kept correct only by the gap between them.Whenever the Host needs its grace period, Desktop's deadline expires first — by construction.This was wrong, and I need to correct it. I audited a snapshot ofmainfrom before #4709, which landed earlier today and already moved the Desktop side to 12s with an explicit comment that the margin exists so Desktop cannot race the Host's finalprocess.exit. Since#requestDrain()is synchronous andprocess-lifecycle.tsexits the moment the deadline fires, the guaranteed-timeout claim does not hold on currentmain. Filed as #4730 before I caught this; corrected there.What still stands is the shape: the coupling is maintained by a margin rather than removed. Finding 1 deletes the Desktop budget outright, so this resolves as a consequence rather than as its own fix.
3. Two smaller lifecycle observations, if they are in scope for this issue.
#retainUntilProcessExit()expresses "this Host must not idle-exit" by taking a residency that is never released.#hasUpgradeBlockingActivity()then has to filter that label back out. Residency currently answers two different questions (block idle exit / block drain), and this is where they collide.#isTrueIdle()does not count#handshakingTransports, while#armInitialConnectionDeadline()explicitly defers for them. A client that connects but stalls mid-handshake is invisible to one timer and visible to the other.4. Off-topic question, feel free to point us elsewhere.
Is
RuntimeHostCompositionthere because a second composition is expected? TodayINTERACTIVE_RUNTIME_HOST_COMPOSITION_IDis the only id, no consumer comparescompositionRevision, andexecution-candidate.tsexists mainly to fill the factory parameter. We could not tell from the code whether that is a planned seam or leftover generality, and did not want to guess.me2seeks commentedon Sep 4, 2026
Verified the three findings against current main; all of them hold structurally.
Confirmed:
#close()releasescandidateLaunchBarrierunconditionally before closing IPC (runtime-host-desktop-manager.ts). I agree the launch-owner guard's disconnect path should be the close authority on quit, and the quit path should not drive retirement at all. That removes the PID-polling step and changes the Desktop slice of the convergence sequence: fix(desktop): retire the owned local Host on full quit #3706's synchronous retirement becomes a transitional wrapper to delete, not a path to keep.Both budgets confirmed: the Host arms its shutdown deadline inside
#requestDrain()whilehost.upgrade.prepareis still being handled, andwaitForProcessExitstarts only after the response. One caveat from reading the code: prepare responds immediately after#requestDrain(), so the Desktop deadline nominally starts after the Host's own — the guaranteed timeout likely also needs the post-deadline exit path (or a stuck residency such as'process-retention') to delay the actual process death. Either way, two independent 10s budgets for one operation is wrong. fix(desktop): quit retirement always times out before the Host can exit #4730 should pin the exact mechanism with a repro; the fix should follow finding 1 rather than tune either timeout.Both confirmed:
'process-retention'is acquired and never released, and#hasUpgradeBlockingActivity()filters that label back out;#isTrueIdle()cannot see#handshakingTransportswhile#armInitialConnectionDeadline()defers for them. Proposal: split residency kinds (block idle-exit vs block drain), and give idle visibility to handshaking transports — folded into the reconciler seam, not patched separately.Composition: the ID is load-bearing as the persistent State Root fence; a root bound to the interactive composition must refuse a different kind.
compositionRevisionis diagnostics-only today — no consumer compares it — and the factory indirection has exactly one inhabitant. My read: the identity stays, the generality is unproven; document it as a deliberate fence and let the reconciler work prove whether a second composition ever arrives.Convergence sequence update: Desktop quit fixes the guard disconnect path and deletes #3706's retirement wrapper instead of keeping it; #4730 tracks the guaranteed-timeout bug until then.