Skip to content

architecture(runtime-host): converge local Host lifecycle through owner-scoped reconciliation #3709

Description

@M4n5ter
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.prepare wire operation.
  • Desktop Quit and Desktop Update share a retirement adapter, but concurrent requests coalesce onto the first policy. A later interrupt_active_work request cannot strengthen an in-flight refuse_active_work request.
  • The returned resume() callback means “allow the owner lifecycle to create a successor after retirement,” not “resume the retired Host.”

#3254 design pressure

  • connectOrSpawn carries 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-task residency, 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:

  1. desired-state policy decides the exact state to converge toward and when reconciliation should run;
  2. explicit, idempotent owner transactions perform staging, retirement, cutover, verification, and recovery;
  3. the narrow Host retirement contract controls admission, active work, drain/interruption, and writer release;
  4. 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 new local owner/reconciliation contracts should be frozen after the near-term #3228 reconciliation core establishes the shared policy, transaction, scheduling, and recovery boundaries.

Architecture principles

  1. One layered reconciliation model. Policy, owner transaction, Host retirement, and platform capability are separate layers with one-way authority flow.
  2. One owner per deployment. A mutation requires positive owner authority; an ordinary Client credential, package path, or successful connection is not deployment authority.
  3. One narrow Host retirement contract. Runtime Host Kernel remains the sole authority for admission, activity, drain, checkpoint/interruption, semantic recovery, and writer release.
  4. One explicit deployment identity. DeploymentIdentity carries source-appropriate verified evidence. Package version remains display and package-manager metadata.
  5. One exact process fence. Every mutation against a present Host targets the observed HostEpoch and fails closed when identity or ownership changes.
  6. Owner-scoped serialization. Process-lifetime owner locks serialize reconciliation and transactions. State Root writer ownership fences the actual cutover.
  7. Bounded capability adapters. Compatible retirement, legacy incompatible takeover, and operator control may use different mechanisms while preserving the same typed semantics and removal conditions.
  8. 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.
  9. 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:

  1. validate owner authority and serialize the owner transition;
  2. resolve an exact desired deployment when running is requested;
  3. inspect the exact current Host through an observed capability adapter;
  4. stage the selected deployment before destructive mutation;
  5. return typed blockers when policy refuses active-work interruption;
  6. fence admission and request checkpoint/drain or explicit interruption;
  7. observe writer release rather than infer retirement from stale registration;
  8. stop at owner-scoped stopped, or activate and launch the selected deployment;
  9. verify successor Root, Host Epoch, deployment identity, and readiness;
  10. 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.

The shared contract should therefore be a small 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:

  1. policy resolves to an exact desired deployment;
  2. bounded one-shot reconciliation delegates to the verified update transaction;
  3. scheduling reuses the same reconciliation entry point;
  4. 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

  1. Land fix(desktop): retire the owned local Host on full quit #3706 as the urgent exact-owner retirement path. Improve concurrent policy escalation without treating its current fail-closed, recoverable behavior as a merge-blocking safety defect.
  2. Keep feat(cli): reconcile local Runtime Host generations #3254 paused while retaining its tests, diagnostics, and released-Host compatibility evidence.
  3. Complete the [Tracking] Managed remote Runtime Host onboarding and lifecycle #3228 reconciliation core.
  4. Identify and extract only the genuinely shared contracts and invariants.
  5. Define the durable local owner record, machine-readable owner transaction surface, and local-process adapter.
  6. Implement owner-scoped local reconciliation over the shared transaction model.
  7. Move replacement policy out of connectOrSpawn and Surface-owned loops.
  8. 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.
  • stopped is always interpreted within an explicit owner scope.
  • Installed CLI/TUI replacement policy is outside ordinary connectOrSpawn admission.
  • 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.prepare as the public lifecycle semantic after its bounded legacy window;
  • replacement-policy fields on ordinary connectOrSpawn calls;
  • 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.prepare wire 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-task residency 时的 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 边界一致时应复用的分层模型:

  1. desired-state policy 决定应收敛到哪个精确状态,以及何时执行 reconciliation;
  2. 显式、幂等的 owner transaction 负责 staging、retirement、cutover、verification 与 recovery;
  3. 窄小的 Host retirement contract 负责 admission、active work、drain/interruption 与 writer release;
  4. 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。新的本地 owner/reconciliation 契约应在近期 #3228 reconciliation core 确立共享 policy、transaction、scheduling 与 recovery 边界后再冻结。

架构原则

  1. 一套分层 reconciliation 模型。 Policy、owner transaction、Host retirement 与 platform capability 是 authority 单向流动的独立层。
  2. 每个 deployment 一个 owner。 Mutation 需要正向 owner authority;普通 Client credential、package path 或成功连接都不是 deployment authority。
  3. 一套窄小的 Host retirement contract。 Runtime Host Kernel 继续独占 admission、activity、drain、checkpoint/interruption、semantic recovery 与 writer release authority。
  4. 一种明确的 deployment identity。 DeploymentIdentity 携带与来源匹配且经过验证的证据;package version 只负责展示与 package-manager metadata。
  5. 一道精确 process fence。 针对 present Host 的每次 mutation 都绑定 observed HostEpoch,identity 或 ownership 改变时 fail closed。
  6. Owner-scoped serialization。 Process-lifetime owner lock 序列化 reconciliation 与 transaction;State Root writer ownership 保护实际 cutover。
  7. 有边界的 capability adapter。 Compatible retirement、legacy incompatible takeover 与 operator control 可以使用不同机制,但必须保持相同 typed semantic 和删除条件。
  8. 薄 Surface adapter。 Desktop dialog 与 TUI prompt 只收集 consent、展示 outcome,不选择 artifact、不拥有 update journal,也不实现 replacement loop。
  9. 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:

  1. 验证 owner authority 并序列化 owner transition;
  2. 请求 running 时解析精确 desired deployment;
  3. 通过观察到的 capability adapter 检查精确 current Host;
  4. 在破坏性 mutation 前 stage selected deployment;
  5. policy 拒绝中断 active work 时返回 typed blocker;
  6. fence admission,并请求 checkpoint/drain 或明确 interruption;
  7. 观察 writer release,而不是从 stale registration 推断 retirement;
  8. 在 owner-scoped stopped 结束,或 activate 并启动 selected deployment;
  9. 验证 successor Root、Host Epoch、deployment identity 与 readiness;
  10. 发布足以支持有界 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 绑定到更新事务。

因此,共享契约应是一个很薄的 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 核心契约稳定:

  1. policy 解析为精确 desired deployment;
  2. bounded one-shot reconciliation 委托给已经验证的 update transaction;
  3. scheduler 复用同一个 reconciliation 入口;
  4. retry 与 recovery outcome 形成稳定的机器契约。

这些契约稳定后,Desktop update-policy UI 或其他剩余 presentation 工作不再构成 architecture gate。

收敛顺序

  1. 合并 fix(desktop): retire the owned local Host on full quit #3706,作为紧急的 exact-owner retirement 路径。改进并发 policy escalation,但不把当前 fail-closed 且可恢复的行为视为阻塞合并的安全缺陷。
  2. 暂停 feat(cli): reconcile local Runtime Host generations #3254,同时保留其中的测试、诊断与 released-Host 兼容性证据。
  3. 完成 [Tracking] Managed remote Runtime Host onboarding and lifecycle #3228 reconciliation core。
  4. 只识别并提取真正共享的契约和 invariant。
  5. 定义 durable local owner record、机器可读 owner transaction surface 与 local-process adapter。
  6. 在共享 transaction model 上实现 owner-scoped local reconciliation。
  7. 将 replacement policy 移出 connectOrSpawn 与 Surface-owned loop。
  8. 为已发布 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 位于普通 connectOrSpawn admission 之外。
  • 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 契约。

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions