Skip to content

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

Closed
1 of 1 issue completed

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 #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

  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.

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:

  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. fix(desktop): retire the owned local Host on full quit #3706 delivered the urgent exact-owner retirement path.
  2. Keep feat(cli): reconcile local Runtime Host generations #3254 paused while retaining its useful diagnostics and released-Host compatibility evidence.
  3. 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.
  4. Land refactor(runtime-host): share verified deployment identity #3766 as the narrow shared verified deployment-identity contract.
  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。#3228 的 policy、transaction、scheduling 与 recovery 边界现已通过 #3720 和 #3747 中的 scheduler adapter 稳定。Draft PR #3766 正在提取共享的 verified deployment-identity 契约,之后再开始 durable local ownership 工作。

架构原则

  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 绑定到更新事务。

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 核心契约稳定:

  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 路径。
  2. feat(cli): reconcile local Runtime Host generations #3254 继续暂停,只保留有价值的诊断与 released-Host 兼容性证据。
  3. 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。
  4. 以 refactor(runtime-host): share verified deployment identity #3766 交付窄小的共享 verified deployment-identity 契约。
  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 契约。

Activity

  1. M4n5ter commented on Aug 24, 2026

    @M4n5ter
    MemberAuthor
    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:

    • whether compatible connected retirement and incompatible startup takeover can safely share one lifecycle state machine;
    • whether lifecycle inspection/retirement needs a stable control plane independent of the Runtime Domain compatibility epoch;
    • whether ordinary connection admission should be separated from artifact selection, candidate launch, and replacement policy currently carried by connectOrSpawn;
    • what should constitute installation-owner authority and immutable ArtifactId across Desktop, installed CLI, development builds, and npx;
    • whether the proposed unified PR is the right atomic architecture change or hides a boundary that must remain separate.

    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 取代。

    最希望得到挑战的部分包括:

    • compatible connected retirement 与 incompatible startup takeover 能否安全共享一个 lifecycle state machine;
    • lifecycle inspection/retirement 是否需要独立于 Runtime Domain compatibility epoch 的稳定 control plane;
    • 普通 connection admission 是否应与 connectOrSpawn 当前承载的 artifact selection、candidate launch 和 replacement policy 分离;
    • Desktop、installed CLI、development build 与 npx 应分别通过什么构成 installation-owner authority 和 immutable ArtifactId;
    • 统一 PR 是否是正确的原子架构变更,或者其中隐藏了必须保持独立的边界。

    如果存在会推翻目标模型的 ownership、compatibility、recovery 或 migration 约束,请直接指出。

  2. me2seeks commented on Aug 24, 2026

    @me2seeks
    Contributor
    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 main has materially different Host control paths:

    • compatible connected retirement uses the authenticated host.upgrade.prepare operation;
    • incompatible generation takeover happens during hello, before Domain admission, and current main permits it only when the Host is truly idle;
    • service-mode replacement remains an operator-plane action.

    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 HostEpoch remain 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. ArtifactId is important, but it is a separate deployment contract

    I agree that package version and the current generation string are not immutable artifact identity. However, a verified ArtifactId must define the runnable closure and provenance across Electron, installed CLI, development builds, and npx. Desktop Quit only requests stopped and does not require artifact selection. Coupling this packaging decision to the urgent #3703 fix would unnecessarily block the availability repair.

    My preferred migration is:

    • allow fix(desktop): retire the owned local Host on full quit #3706 to land as the narrow compatible-owner retirement fix, after resolving policy escalation and keeping its retirement wrapper explicitly transitional;
    • keep feat(cli): reconcile local Runtime Host generations #3254 paused as implementation evidence rather than mark it Ready;
    • introduce the reconciler seam next and move replacement policy out of ordinary connectOrSpawn;
    • add durable installation ownership, immutable artifact identity, and the future stable lifecycle control plane in separately reviewable changes;
    • then remove the bounded legacy adapters.

    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 控制路径:

    • compatible connected retirement 使用已认证的 host.upgrade.prepare operation;
    • incompatible generation takeover 发生在 hello 阶段、Domain admission 之前,并且当前 main 只允许真正 idle 的 Host 被接管;
    • service-mode replacement 仍属于 operator plane action。

    独立于 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 修复绑定,会不必要地阻塞启动可用性修复。

    我倾向的迁移顺序是:

    • 在解决 policy escalation,并明确 retirement wrapper 只是过渡 adapter 后,让 fix(desktop): retire the owned local Host on full quit #3706 作为窄小的 compatible-owner retirement 修复落地;
    • 让 feat(cli): reconcile local Runtime Host generations #3254 保持暂停并作为实现证据,不按现状转为 Ready;
    • 下一步引入 reconciler seam,并把 replacement policy 从普通 connectOrSpawn 中移出;
    • 通过可独立评审的变更补充 durable installation ownership、immutable artifact identity 和未来的稳定 lifecycle control plane;
    • 最后删除有界 legacy adapter。

    这样可以得到一个长期 authority 和 interface,同时不要求所有迁移问题都塞进一个大型 PR。是否可以把 #3709 定义为目标架构与明确的收敛顺序,而不是要求一个原子化 replacement PR?

  3. M4n5ter commented on Aug 24, 2026

    @M4n5ter
    MemberAuthor
    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:

    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 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 | next policy 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:

    type DesiredOwnedHostState =
      | { kind: 'stopped' }
      | { kind: 'running'; deployment: DeploymentIdentity };
    
    reconcileOwnedHost({
      owner,
      rootId,
      expectedHostEpoch,
      desiredState,
      activeWorkPolicy,
    });

    stopped means 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:

    • inspect authoritative activity and recovery facts;
    • target the exact authenticated HostEpoch;
    • stop admission;
    • settle, checkpoint, or explicitly interrupt active work;
    • release the State Root writer;
    • return a typed and truthful terminal result.

    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 DeploymentIdentity envelope 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

    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:

    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.

    A practical convergence sequence is therefore:

    1. land fix(desktop): retire the owned local Host on full quit #3706;
    2. keep feat(cli): reconcile local Runtime Host generations #3254 paused while retaining its tests and 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 and local-process adapter;
    6. implement owner-scoped local reconciliation over the shared transaction model;
    7. move replacement policy out of connection election;
    8. retain bounded adapters for released Hosts and remove them when the stable owner control capability is broadly available.

    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 模型:

    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、精确 identity fencing、readiness verification 与真实的 retry recovery。剩余的 manual | fixed | latest | next policy 和 scheduler 将在这些事务之上增加 bounded 与 periodic desired-state reconciliation。

    Reconciliation 边界

    共享 reconciliation model 仍然是正确目标,但 reconciliation 必须限定在 owner 作用域内:

    type DesiredOwnedHostState =
      | { kind: 'stopped' }
      | { kind: 'running'; deployment: DeploymentIdentity };
    
    reconcileOwnedHost({
      owner,
      rootId,
      expectedHostEpoch,
      desiredState,
      activeWorkPolicy,
    });

    stopped 表示由指定 owner 拥有的 Host 已经退场。它不表示 State Root 必须全局保持停止,也不表示另一个经过授权的 owner 永远不能启动 successor。

    Reconciler 负责决定收敛计划并调用显式 owner transaction。它不会取代这些事务,也不会把事务 authority 移入 Host Kernel。

    共享 retirement contract

    长期稳定的 Runtime primitive 应保持窄小:

    • 检查权威的 activity 与 recovery facts;
    • 绑定经过认证的精确 HostEpoch;
    • 停止 admission;
    • 收敛、checkpoint 或明确中断 active work;
    • 释放 State Root writer;
    • 返回类型化且真实的最终结果。

    兼容 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 绑定到更新事务。

    剩余契约应当是一个很薄的 DeploymentIdentity envelope,携带与来源匹配且经过验证的证据。临时 invocation 来源的 ownership 与生命周期语义仍属于独立的产品决策,不是 #3703 或本次收敛的前置条件。

    Deployment identity 仍是 installation/deployment concern。它应参与 running(exactDeployment) reconciliation,但不能成为 Host retirement 的组成部分,也不应阻塞 Desktop Quit。

    交付决策

    这是一个范围明确的 architecture gate,并不要求等待 #3228 的所有产品界面。以下契约稳定后即可开始本地实现:

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

    因此,实际收敛顺序是:

    1. 合并 fix(desktop): retire the owned local Host on full quit #3706;
    2. 暂停 feat(cli): reconcile local Runtime Host generations #3254,同时保留其中的测试和兼容性证据;
    3. 完成 [Tracking] Managed remote Runtime Host onboarding and lifecycle #3228 reconciliation core;
    4. 只识别并提取真正共享的契约和 invariant;
    5. 定义 durable local owner record 与 local-process adapter;
    6. 在共享 transaction model 上实现 owner-scoped local reconciliation;
    7. 将 replacement policy 移出 connection election;
    8. 为已发布 Host 保留有界 adapter,并在稳定 owner control capability 广泛可用后删除。

    AI agent 辅助开发使这个短期 design gate 的成本很低,并能在边界稳定后快速完成整组实现。没有必要在参考 reconciliation model 即将完成前冻结一套平行抽象,也没有必要把不同的 authority、protocol、deployment 与 recovery 变更合并成一个过大的评审单元。

    因此,#3709 应调整为目标架构与收敛顺序。真正的目标是:一套分层 reconciliation 模型、每个 deployment 一个 owner、显式幂等的 owner transaction、一套窄小的 Host retirement contract,以及有边界的 capability adapter。

  4. changed the title [-]architecture(runtime-host): unify local Host reconciliation across quit, update, and incompatible startup[/-] [+]architecture(runtime-host): converge local Host lifecycle through owner-scoped reconciliation[/+] on Aug 24, 2026
  5. me2seeks commented on Aug 24, 2026

    @me2seeks
    Contributor

    感谢澄清。我核对了 #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 事实。

  6. me2seeks commented on Aug 24, 2026

    @me2seeks
    Contributor
    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

    • HostRegistration publishes rootId, hostEpoch, compatibility/protocol facts, lifecycle mode, optional generation, and PID. It does not publish a deployment owner.
    • The State Root writer lease is the final single-writer fence. It proves which process currently writes the Root, not which installation may replace that process.
    • The managed-service path has exact target checks and process-lifetime lifecycle/deployment locks. No equivalent durable local Desktop/CLI owner record exists.
    • fix(desktop): retire the owned local Host on full quit #3706 now gives the Desktop-owned compatible ephemeral Host an exact authenticated retirement path. It does not establish transferable durable deployment ownership.
    • feat(cli): reconcile local Runtime Host generations #3254 treats “persistent rather than _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.
    • Remote profiles only connect. Their Client credential does not authorize service mutation.

    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:

    type InstallationOwner = {
      installationId: string; // stable across that installation's artifact updates
      kind: 'desktop' | 'cli' | 'managed_service' | 'development';
    };
    
    type LocalHostDeploymentRecord = {
      schemaVersion: 1;
      rootId: string;
      revision: string; // opaque CAS token
      state:
        | {
            kind: 'owned';
            owner: InstallationOwner;
            selected: DeploymentIdentity;
            previous?: DeploymentIdentity;
          }
        | {
            kind: 'transferring';
            transactionId: string;
            from: InstallationOwner;
            to: InstallationOwner;
            target: DeploymentIdentity;
            previous?: DeploymentIdentity;
          };
    };

    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. DeploymentIdentity carries 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

    Caller/source Initial claim when no record exists Mutating an existing different owner
    Verified persistent Desktop MAY establish its stable Desktop installation owner explicit transfer only
    Verified persistent installed CLI MAY establish its stable CLI installation owner explicit transfer only
    npx ... runtime-host setup MAY stage the exact invoked release, but the resulting managed deployment/service—not _npx—becomes owner explicit operator transfer only
    direct npx maka MUST NOT create or mutate the durable record never; connect/wait/cancel only against another owner
    development checkout MUST NOT claim silently; an explicit development claim MAY be supported with a visibly non-release identity explicit transfer, never last-launch-wins
    ordinary local/remote Client credential no no
    compatibility or epoch mismatch no no; mismatch is evidence, not authority

    “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

    1. Claim: if no record exists, a verified persistent installation creates owned under the authority lock using create-if-absent/CAS. A loser re-reads; it does not overwrite.
    2. Ordinary connect: any compatible Client may connect without becoming owner or changing the record.
    3. Same-owner reconcile: the recorded owner may stage an exact deployment and reconcile it through an owner transaction.
    4. Different-owner mutation: return owner_transfer_required with bounded owner/deployment facts. Do not infer consent from package installation or successful connection.
    5. Transfer: stage and verify the target first; acquire the one authority lock; CAS the observed revision; persist explicit transfer intent; retire the exact observed Host through a capability adapter; observe writer release; select/launch/verify the target; then commit owned(to).
    6. Crash recovery: a durable transferring state is recovered by re-observing the owner record, actual Host, writer lease, and artifacts. It never continues from a persisted PID or HostEpoch. Before durable transfer intent, the old owner remains authoritative; after it, neither installation may start an unrelated writer outside the transaction.
    7. Uninstall: removing a non-owner artifact changes no owner state. Uninstalling the active owner must first complete an explicit transfer or retire its Host and clear the owner record. State Root deletion is a separate destructive action.

    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_required plus 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 maka starts 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, npx must 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 _npx cache 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 manual or 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.

    Case Required assertion
    Two persistent installations race to claim an absent record exactly one create-if-absent wins; loser re-reads and cannot mutate
    Desktop owner + compatible global CLI connect succeeds; owner revision and selected deployment do not change
    Desktop owner + incompatible CLI no takeover before explicit transfer consent and owner-revision CAS
    Owner changes between prompt and confirmation stale confirmation fails with owner_changed; no Host is retired
    Host changes between inspection and retirement stale HostEpoch fails closed; transaction re-observes
    Same epoch, different exact deployment ordinary connect is allowed; only an explicit owner action replaces
    Different epoch, idle Host bounded legacy or stable-control adapter retires the exact Host; one successor writer becomes Ready
    Different epoch, active external effect no automatic interruption; explicit policy preserves result_unknown semantics
    direct npx exits normally invocation-owned Host retires; no durable owner record or background residency remains
    direct npx is killed/crashes liveness handle closes and Host retires without relying on cache or parent PID reuse
    _npx cache is deleted while invocation runs live code remains valid only for the invocation; no restartable durable Host depends on the deleted path
    explicit npx setup then cache deletion systemd/LaunchAgent starts only the verified managed copy
    owner artifact disappears no automatic claim; explicit orphan recovery/transfer is required
    transfer crashes before durable intent old owner remains authoritative
    transfer crashes after retirement before target Ready transferring recovery re-observes writer/artifacts and completes or reports degraded state truthfully
    candidate fails Ready verification it is not committed as owned(selected); previous verified artifact is retained where storage compatibility permits
    uninstall non-owner owner record, Host, and State Root remain unchanged
    uninstall current owner transfer or explicit retire-and-release occurs before owner record removal; State Root is retained
    systemd/LaunchAgent restarts service uses its managed deployment and operator authority; no Surface silently claims ownership
    development build meets persistent owner connect if compatible; otherwise explicit development transfer only, with a non-release identity
    remote Client sees incompatibility no stop/update request is sent; operator guidance names the remote owner boundary
    old released Host lacks stable lifecycle control select a bounded legacy adapter by observed capability; never pretend the new control plane exists retroactively
    two OS accounts/machines target one Root no active-active promise; State Root writer lease remains the final fail-closed fence

    Consequence 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 ordinary connectOrSpawn should 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。
    • State Root writer lease 是最终单写者 fence;它证明当前哪个进程在写 Root,不证明哪个 installation 有权替换该进程。
    • Managed-service 路径已有精确 target 检查和 process-lifetime lifecycle/deployment lock;Desktop/CLI 尚无等价的 durable local owner record。
    • fix(desktop): retire the owned local Host on full quit #3706 已为 Desktop-owned compatible ephemeral Host 提供绑定精确认证身份的 retirement,但没有建立可 transfer 的 durable deployment ownership。
    • feat(cli): reconcile local Runtime Host generations #3254 把“不是 _npx”近似为 replacement eligibility,并把 package version/development UUID 近似为 generation。这些是有用的负向 guard 与诊断,不是正向 durable-owner 或 verified-deployment 证据。
    • Remote profile 只负责连接;Client credential 不授权 service mutation。

    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 编码不是本次决定。最小语义结构是:

    type InstallationOwner = {
      installationId: string; // 跨该 installation 的 artifact update 保持稳定
      kind: 'desktop' | 'cli' | 'managed_service' | 'development';
    };
    
    type LocalHostDeploymentRecord = {
      schemaVersion: 1;
      rootId: string;
      revision: string; // opaque CAS token
      state:
        | {
            kind: 'owned';
            owner: InstallationOwner;
            selected: DeploymentIdentity;
            previous?: DeploymentIdentity;
          }
        | {
            kind: 'transferring';
            transactionId: string;
            from: InstallationOwner;
            to: InstallationOwner;
            target: DeploymentIdentity;
            previous?: DeploymentIdentity;
          };
    };

    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 规则

    Caller/source 无记录时建立初始 owner 修改不同的现有 owner
    经过验证的 persistent Desktop 可以建立稳定 Desktop installation owner 只能显式 transfer
    经过验证的 persistent installed CLI 可以建立稳定 CLI installation owner 只能显式 transfer
    npx ... runtime-host setup 可以 stage 本次精确 release,但 owner 是最终 managed deployment/service,不是 _npx 只能由 operator 显式 transfer
    direct npx maka 不得创建或修改 durable record 永不允许;面对其他 owner 只能 connect/wait/cancel
    development checkout 不得静默 claim;可以支持带明显 non-release identity 的显式 development claim 显式 transfer,禁止 last-launch-wins
    普通 local/remote Client credential 不允许 不允许
    compatibility 或 epoch mismatch 不允许 不允许;mismatch 是证据,不是 authority

    “Verified persistent”必须表示 runnable closure 已拥有来源匹配的 DeploymentIdentity。仅仅不位于 _npx、路径稳定或能报告 version 都不够。

    状态转换

    1. Claim: 没有记录时,verified persistent installation 在 authority lock 下以 create-if-absent/CAS 创建 owned。竞争失败者重新读取,不覆盖。
    2. 普通连接: compatible Client 可以连接,但不会成为 owner,也不修改记录。
    3. 同 owner reconcile: 记录中的 owner 可以 stage 精确 deployment,并通过 owner transaction 收敛。
    4. 不同 owner mutation: 返回带有界 owner/deployment facts 的 owner_transfer_required。不能从 package 安装或成功连接推断 consent。
    5. Transfer: 先 stage/verify target;取得唯一 authority lock;CAS observed revision;持久化显式 transfer intent;通过 capability adapter 让精确 observed Host retirement;观察 writer release;select/launch/verify target;最后提交 owned(to)。
    6. Crash recovery: durable transferring 状态通过重新观察 owner record、实际 Host、writer lease 与 artifact 恢复;绝不从持久 PID 或 HostEpoch 续跑。Transfer intent 持久化前,旧 owner 仍有 authority;持久化后,两边都不能绕开 transaction 启动无关 writer。
    7. Uninstall: 删除非 owner artifact 不改变 owner state。卸载 active owner 前必须先完成显式 transfer,或让其 Host retirement 后清除 owner record。State Root 删除是另一项 destructive action。

    只需要一把 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;_npx cache 永远不是 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 测试。

    场景 必须断言
    两个 persistent installation 竞争建立空 owner record create-if-absent 只有一个成功;失败者重读且不能 mutation
    Desktop owner + compatible global CLI connect 成功;owner revision 与 selected deployment 不变
    Desktop owner + incompatible CLI 显式 transfer consent 与 owner-revision CAS 前不得 takeover
    prompt 后、确认前 owner 变化 stale confirmation 返回 owner_changed;不 retirement Host
    inspection 后、retirement 前 Host 变化 stale HostEpoch fail closed,并重新观察
    same epoch、不同 exact deployment 普通连接允许;只有显式 owner action 才替换
    different epoch、idle Host bounded legacy 或 stable-control adapter 让精确 Host 退场;successor 成为唯一 Ready writer
    different epoch、active external effect 不自动中断;显式 policy 保留 result_unknown 语义
    direct npx 正常退出 invocation-owned Host 退场;不留下 durable owner record 或 background residency
    direct npx 被 kill/crash liveness handle 关闭并触发 Host 退场,不依赖 cache 或可复用 parent PID
    invocation 运行中 _npx cache 被删除 live code 只保证到 invocation 结束;不会留下依赖消失路径的 restartable durable Host
    显式 npx setup 后删除 cache systemd/LaunchAgent 只从 verified managed copy 启动
    owner artifact 消失 不自动 claim;要求显式 orphan recovery/transfer
    transfer 在 durable intent 前 crash 旧 owner 继续有效
    retirement 后、target Ready 前 crash transferring recovery 重验 writer/artifact,并完成或真实报告 degraded state
    candidate Ready verification 失败 不提交 owned(selected);storage compatibility 允许时保留 previous verified artifact
    uninstall 非 owner owner record、Host 与 State Root 均不变
    uninstall 当前 owner 删除 owner record 前先 transfer 或显式 retire/release;State Root 保留
    systemd/LaunchAgent restart service 使用自己的 managed deployment/operator authority;Surface 不静默 claim
    development build 遇到 persistent owner compatible 时连接;否则只能显式 development transfer,并使用 non-release identity
    remote Client incompatibility 不发送 stop/update;operator guidance 明确 remote owner 边界
    已发布旧 Host 没有 stable lifecycle control 按观察到的 capability 选择 bounded legacy adapter,不假装旧版本拥有新 control plane
    两个 OS account/机器针对同一 Root 不承诺 active-active;最终由 State Root writer lease fail closed

    对 #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 的实现与测试。

  7. me2seeks commented on Aug 25, 2026

    @me2seeks
    Contributor
    English

    Local owner implementation update

    I split the first implementation step into two dependency-ordered PRs:

    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:

    • infer authority from package paths, compatibility, version, PID, or HostEpoch;
    • let direct npx or an ordinary remote Client create durable ownership;
    • define speculative Desktop/development artifact evidence;
    • retire a Host, launch a successor, or add Desktop/CLI/TUI/systemd/remote adapters.

    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:

    拆分依据是 authority 边界,不是文件数量。Deployment evidence 可以独立且保持行为不变;owner state、locking、transition、persistence 与跨进程竞争测试必须放在一起,否则会产生只有部分权威性的记录。

    Owner PR 不会从 package path、compatibility、version、PID 或 HostEpoch 推断 authority;direct npx 与普通 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

  8. me2seeks commented on Aug 25, 2026

    @me2seeks
    Contributor
    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:

    1. stage and verify the exact target before durable intent;
    2. CAS the observed owner revision and persist transferring;
    3. re-observe the actual local Host through a source-specific capability adapter;
    4. retire only the previous Host, then observe State Root writer release;
    5. activate and verify the exact transaction-scoped target as Ready;
    6. commit the target installation as 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 preserve transferring; only an active_work refusal 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:

    • The simplification audit removed the unused distinction between “previous retired” and “Host absent”; both are one target_absent observation.
    • The first-principles/Occam audit retained only durable transfer intent, one owner lock, the existing writer fence, and source-specific capabilities. It rejected a second deployment journal, daemon, remote mutation path, and version/epoch-derived authority.

    The adapter boundary is intentionally still explicit:

    • Desktop/installed CLI candidates may use a transaction-scoped launch fence to distinguish the exact target attempt.
    • systemd/LaunchAgent must quiesce its supervisor and prove the managed deployment through its operator-owned evidence before reporting the target present.
    • direct npx maka cannot call this durable-owner path; explicit npx ... runtime-host setup may stage a managed persistent deployment, whose managed installation—not _npx—participates as owner.
    • a remote Client cannot invoke local owner transfer. Remote Host update remains an explicit action by the deployment operator on the Host machine.

    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 main and retain only the transaction commit.

    Verification: the complete @maka/runtime-host suite 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

  9. added theissue type on Aug 29, 2026
  10. Astro-Han commented on Sep 4, 2026

    @Astro-Han
    Contributor

    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 calls candidateLaunchBarrier?.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() while host.upgrade.prepare is still being handled; Desktop's waitForProcessExit deadline 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 of main from 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 final process.exit. Since #requestDrain() is synchronous and process-lifecycle.ts exits the moment the deadline fires, the guaranteed-timeout claim does not hold on current main. 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 RuntimeHostComposition there because a second composition is expected? Today INTERACTIVE_RUNTIME_HOST_COMPOSITION_ID is the only id, no consumer compares compositionRevision, and execution-candidate.ts exists 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.

  11. me2seeks commented on Sep 4, 2026

    @me2seeks
    Contributor

    Verified the three findings against current main; all of them hold structurally.

    1. Confirmed: #close() releases candidateLaunchBarrier unconditionally 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.

    2. Both budgets confirmed: the Host arms its shutdown deadline inside #requestDrain() while host.upgrade.prepare is still being handled, and waitForProcessExit starts 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.

    3. Both confirmed: 'process-retention' is acquired and never released, and #hasUpgradeBlockingActivity() filters that label back out; #isTrueIdle() cannot see #handshakingTransports while #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.

    4. Composition: the ID is load-bearing as the persistent State Root fence; a root bound to the interactive composition must refuse a different kind. compositionRevision is 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.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions