Skip to content

feat(cli): coordinate npm-global Runtime Host updates - #3925

Merged
likun666661 merged 6 commits into
apache:mainfrom
me2seeks:feat/cli-installed-runtime-host-update
Aug 28, 2026
Merged

feat(cli): coordinate npm-global Runtime Host updates#3925
likun666661 merged 6 commits into
apache:mainfrom
me2seeks:feat/cli-installed-runtime-host-update

Conversation

@me2seeks

Copy link
Copy Markdown
Contributor

Summary

  • add an explicit maka update --target <next|latest|version> path for an npm-global CLI and its local Runtime Host
  • acquire and revalidate the exact official npm archive, stage the target immutably, retire the current Host with the current protocol, and activate the target with the target protocol
  • serialize target Ready verification, npm-global package switching, and owner commit in the existing deployment-authority transaction
  • keep the existing authority lease inherited by activation and package-switch children so a coordinator crash cannot admit a competing owner mutation

User-visible behavior

The command is deliberately explicit: direct npx/development launches, downgrades, remote Hosts, and operator-managed services fail closed. Active work is refused by default; --allow-interrupt-active-tasks is required to authorize interruption.

This preserves the existing ownership boundary: local npm-global deployments can be coordinated by the installed CLI, while remote and service-managed Hosts remain operator-updated.

Why this is one vertical PR

The shared registry-artifact seam and deployment-source finalization now each have a concrete production consumer. Splitting them before the caller would leave speculative abstractions or an incomplete transaction. The implementation still keeps three small process roles because each has a distinct compatibility constraint:

  1. a native-free bootstrap survives Windows npm self-replacement;
  2. a copied current-package coordinator speaks to and retires the current Host;
  3. a staged target-package activator speaks the target epoch and proves exact Ready.

There remains one durable owner record, one handoff transaction, and one authority lock. No scheduler, second deployment journal, or parallel ownership state is introduced.

Failure and recovery

  • activation, package switching, or post-install verification failures leave durable handoff truth for the existing recovery path
  • the inherited authority lease keeps the transaction serialized if the coordinator exits while a child still owns the in-flight operation
  • the npm install uses the exact verified local archive, offline mode, ignored scripts, and an isolated cache, then verifies the same global owner slot and exact target version before commit

Validation

  • built @maka/core, @maka/storage, @maka/mcp, @maka/runtime, @maka/runtime-host, @maka/eval, @maka/computer-use, and maka-agent
  • typechecked storage, Runtime Host, and CLI
  • focused changed-path tests: 37/37 passed
  • scoped CLI release-policy tests: 38/38 passed
  • scoped Biome: 23 files passed
  • native-free cli-core process probe passed
  • git diff --check passed
  • exact published-package probe installed a packed maka-agent@next tarball into an isolated npm-global prefix with offline/script-disabled settings and verified the installed version and binary

The full check:release command was not used as evidence because its repository-wide stale-dist preflight requires unrelated UI/Desktop build outputs; the scoped release-policy tests above pass.

Follow-ups outside this slice

  • reconcile external npm mutations beyond the existing deployment-owner recovery path
  • direct npx ownership and lifecycle
  • broader Desktop/TUI presentation
  • released-version persisted-root qualification across migration/epoch combinations

Refs #3231
Refs #3243
Refs #3245
Refs #3709

中文说明

本 PR 为 npm 全局安装的 CLI 增加显式 maka update --target <next|latest|version>:复用现有 owner authority、handoff 事务和锁,依次完成旧 Host 退场、目标版本精确 Ready、npm 全局包切换与 owner 提交。

默认拒绝中断活跃工作;只有用户显式传入 --allow-interrupt-active-tasks 才允许。直接 npx、开发环境、降级、remote Host 和由服务管理器托管的 Host 都会 fail closed,继续由用户或运维方主动更新。

三进程并非重复设计:native-free bootstrap 解决 Windows 自替换;当前包 coordinator 负责当前协议;目标包 activator 负责跨 epoch 的目标协议。系统仍只有一份持久 owner 状态、一条 handoff 事务和一把 authority 锁,没有新增 scheduler 或第二套恢复日志。

终审已按 simplify-audit 与第一性原理/奥卡姆剃刀完成,结论为 GO。

Generated-by: Codex

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this head and found no blocking issues.

Implements npm-global Host update coordination via bootstrap→coordinator→activator with verified archive, integrity-checked local npm install, prepare-then-reconcile transaction checks, lease FD heredity and triple identity verification; hosted test/windows_recovery/audit/owner checks SUCCESS.

No P0-P3.

简体中文该头无阻断。

Automated review notice: This comment was posted by an automated review agent operated by Astro-Han. It is not an independent human review and does not replace one.

@jackwener jackwener left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed exact head c68327b27ead94469cbf2b47fc98aaf7042417a2 and found one blocking issue.

P2 — The verified archive has no extracted-size or file-count budget

validateArchive() limits only the compressed .tgz to 256 MiB. The same archive is then passed to npm install once for staging (packages/cli/src/runtime-host-update-package.ts:141-168) and again for the npm-global switch (packages/cli/src/runtime-host-installed-update-coordinator.ts:259-300) without any bound on extracted bytes, entry count, or filesystem consumption.

SHA-512 integrity proves that the archive matches the registry metadata; it does not make the archive's expansion safe. A broken or compromised official publish can therefore use a small valid archive to exhaust the user's disk during the explicit update. If this happens during the final global switch, the target Host has already been activated and the durable handoff remains incomplete while the installed CLI switch has failed.

Please enforce a total uncompressed-byte and entry-count budget before or during extraction, apply the same bound to the final npm-global installation, and add a regression using a small compressed archive with excessive expansion. The exact-head hosted checks succeeded, but the package tests cover archive integrity and release identity rather than this resource boundary.


Posted by an automated review agent operated by @WAWQAQ. This is not an
independent human review and does not satisfy the committer review required by
CONTRIBUTING.md. A human is accountable for this comment — please push back if
anything here is wrong.

简体中文

本条评论由 @WAWQAQ 运行的自动化审查程序发出。它不构成 CONTRIBUTING.md
所要求的独立人类审查,也不能替代人类审查。有人类对本条评论负责,如有错误请直接指出。

@github-actions github-actions Bot added the effort/XL Over 1000 readable lines label Aug 27, 2026
@me2seeks
me2seeks force-pushed the feat/cli-installed-runtime-host-update branch from c68327b to e583c5b Compare August 27, 2026 10:31
@Astro-Han

Copy link
Copy Markdown
Contributor

This is a synthesis of the independent blind review by @未开智选手 at exact head 7e292bd3805378f7eecd40b03345269c2847db56 (base a5c2631e08cd635e55aff8909cb9298a92702e3a, 25 files +2076/-242). I verified the diff and the exact-head CI myself; the file:line findings below are from the reviewer's sealed report.

What I checked myself:

  • Compared gh pr diff 3925 (npm-global Runtime Host coordination/update, 25 files) and confirmed the archive streaming, handoff retry, and lease chains at runtime-host-update-package.ts:242-260, runtime-host-installed-update-coordinator.ts:133-160 and 311-340, local-process-deployment-handoff.ts:235-267, client/connect-or-spawn.ts:68-82, launcher.ts:120-155.
  • Checked exact-head CI: test run 33069130985 SUCCESS, windows_recovery run 33069130969 SUCCESS, audit SUCCESS, owner macOS/Windows SUCCESS, all 4 Build direct-peer plus 5 Validate installed CLI SUCCESS, all 16 checks green, OPEN/MERGEABLE/BLOCKED/REVIEW_REQUIRED.

Findings from the reviewer's report (file:line anchored):

Overall — CODE NO-GO — 3×P1 — should not be merged as npm-global coordination.

  • P1 — A valid archive is widely rejected by the streaming scannerpackages/cli/src/runtime-host-update-package.ts:242-260 parses a tar header and then skips the entire entry regardless of whether pending already contains the full payload plus padding. Under createGunzip() 16 KiB chunks, a legitimate 128 KiB tar entry was reproduced as rejected (chunks [16384,16384] followed by treating payload as a header and reporting malformed). The scanner runs before both staging and the final npm-global switch, so any normal release containing a file larger than a single chunk cannot be updated. Existing coverage in runtime-host-update-package.test.ts:48-59,252-324 only exercises tiny bodies. The scanner should keep entry state across chunks as a true streaming tar parser and add a cross-chunk regression test.

  • P1 — After activation but before commit_handoff, a crash can roll the durable authority back to a retired Host on retrypackages/cli/src/runtime-host-installed-update-coordinator.ts:133-160 does not recognize “the currently observed Host is already this transaction's target” via staged.launchGeneration; it instead issues another prepareRetirement against the observed Host. When the retry reaches local-process-deployment-handoff.ts:235-267 and finds the target already has active work, the generic rollback writes handoffRecord.state.selected back. If the first switch already retired the old Host and the target is still running, the durable record and the actual Host diverge; when the target is idle it is pointlessly retired and re-activated. Before retiring, the coordinator must verify root/generation, return target_present precisely, and cover both idle and active crash-retry tests before commit.

  • P1 — The authority lease is not passed to the detached targetwithProcessLifetimeFileUpdateLock explicitly requires an inherited fd to keep serialization across parent crashes. The coordinator at runtime-host-installed-update-coordinator.ts:311-340 only passes fd 3 to the activator, but connectOrSpawn (packages/runtime-host/src/client/connect-or-spawn.ts:68-82) has no lease field in its input, and launcher.ts:120-155 ultimately starts the detached Host with stdio: ['ignore','ignore','pipe'] — so after the activator exits the target cannot hold the lease. If the coordinator/activator then fails, the target can stay alive while the durable record remains handoff, letting a later update take the lock and mutate concurrently with the live target. The lease must flow through the candidate-launch contract and stdio, or activation failure must guarantee the candidate does not stay alive, with parent/activator-death tests.

What was proven green: hosted test/windows_recovery/audit/owner/Build/Validate are all green, and no other P0–P3 beyond the three P1s was raised in this slice. No new GitHub review was written by this agent; full evidence is in notes/pr-3925-review.md.

What I did not judge: end-to-end npm-global switch with a real staged candidate on Windows/macOS/Linux was not executed — verification was by code inspection against the exact head and the three fault-chain reproductions noted above.

Gate: 3×P1 remain; despite all 16 hosted checks green, head 7e292bd is not merge-ready as “npm-global Runtime Host coordination” until the streaming scanner is made stateful, the handoff retry respects launch generation, and the lease is carried to the detached target.


Automated review notice: This comment was posted by an automated review agent operated by Astro-Han. It is not an independent human review and does not replace one.

@jackwener jackwener left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I re-reviewed exact head 7e292bd3805378f7eecd40b03345269c2847db56. This head remains NO-GO with three P1 issues and one P2. I independently confirmed the three P1 paths already described in the issue discussion and found the additional PAX bypass below.

  1. P1 — the archive preflight rejects ordinary valid packages. assertRuntimeHostArchiveExpansionBudget() advances past an entry's entire declared body even when the current gunzip chunk contains only part of it. The next chunk therefore starts in the middle of the body but is parsed as another tar header. A valid archive containing a 128 KiB file is rejected as a malformed header before either staging or the final global install can run. The scanner needs to retain body/padding state across chunks, with a cross-chunk regression at both npm seams.

  2. P1 — a crash retry can restore durable ownership to the retired source Host. After target activation but before commit_handoff, retry preparation does not recognize that the observed Host already has the staged target generation. It re-runs retirement against that Host. If the target has work, generic rollback restores the old selected source record even though that source was retired and the target remains live; if the target is idle, it is unnecessarily retired and restarted. Please identify the exact staged target by root and launch generation and cover idle and active crash-retry cases.

  3. P1 — the process-lifetime authority lease stops at the activator. The coordinator passes the lease descriptor to the activator, but the detached target-launch contract has no lease field and starts the Host with only the three ordinary stdio descriptors. If the coordinator or activator dies after the target is live but before the durable record commits, the target can survive without the lease while another coordinator acquires authority over the unresolved handoff. The descriptor must reach the detached target, or failure must guarantee that the target cannot survive; add a parent/activator-death test.

  4. P2 — PAX size overrides bypass the extraction budget. The scanner charges only each raw header's octal size, while npm's tar extractor honors a standard PAX extended header's effective size for the following file. I reproduced this through the production helper with a valid 226-byte npm package tarball: the raw file header declared zero, PAX declared 2,048 bytes, the helper accepted it under a 1,024-byte budget, and npm install wrote the full 2,048-byte file. The same structure scales past the production 2 GiB limit while remaining highly compressible. Parse the archive with the extractor's PAX/global-PAX and sparse-file semantics—or reject unsupported extensions—and prove with a real PAX fixture that npm is never spawned.

The current-main synthetic merge is clean. The exact-head hosted checks succeeded where they ran; the Eval installation check was skipped and is not counted as green. The focused archive/coordinator tests passed 7/7 locally, but they exercise only tiny fixed-octal entries and miss both scanner failures.


Posted by an automated review agent operated by @WAWQAQ. This is not an
independent human review and does not satisfy the committer review required by
CONTRIBUTING.md. A human is accountable for this comment — please push back if
anything here is wrong.

简体中文

本条评论由 @WAWQAQ 运行的自动化审查程序发出。它不构成 CONTRIBUTING.md
所要求的独立人类审查,也不能替代人类审查。有人类对本条评论负责,如有错误请直接指出。

@jackwener
jackwener requested a review from Astro-Han August 28, 2026 04:15
Registry integrity binds the downloaded .tgz to its metadata but says
nothing about how far it expands: a small valid archive could exhaust the
user's disk during staging or the final npm-global switch. Scan the tar
headers (one pass over the compressed stream, nothing written) and refuse
archives whose entries exceed a 2 GiB / 100k-entry budget before npm
install consumes them, at both the verified-artifact seam and the global
switch itself. Regression tests pin over-budget, over-crowded, non-gzip,
and truncated archives.
@me2seeks
me2seeks force-pushed the feat/cli-installed-runtime-host-update branch from 7e292bd to 3716688 Compare August 28, 2026 04:39
@me2seeks

Copy link
Copy Markdown
Contributor Author

Addressed the latest review on exact head 3716688a1f3d1d4634295b54e0df07b084befc64 and rebased onto current main (b6b647cf6369d94ca1a38691e8d1a332b4926662).

The four findings were valid:

  1. The tar budget scanner now carries payload/padding state across gunzip chunks. A 128 KiB cross-chunk fixture proves valid archives are accepted and still rejected when one byte over budget.
  2. Crash retry recognizes the exact staged target generation, verifies its Ready state, and resumes the same handoff without retiring it or restoring the retired source selection. Idle/active and already-switched-package paths are covered.
  3. The existing authority lease now reaches the target Candidate. The Candidate keeps the same lease until durable owner commit; launch-owner loss closes the Host before releasing the lease. A production-process regression kills the launch owner and proves the target exits. No second lock or authority was added.
  4. Extended tar forms that can reinterpret size/path semantics (PAX/global-PAX, GNU sparse/long-name variants) are rejected before either npm extraction seam can spawn. The final npm-global switch independently re-runs the same preflight.

The main conflicts were resolved by retaining current-main's managed activation/managed launch claim and shared npm deployment-layout authority alongside this PR's installed-update path.

Post-rebase evidence:

  • all affected workspace builds and storage/Runtime Host/CLI typechecks passed
  • focused changed-path tests: 62/62 passed
  • isolated owned-Candidate tests: 11/11 passed
  • real launch-owner-death regression passed
  • scoped CLI release-policy tests: 38/38 passed
  • scoped Biome (30 files), native-free cli-core probe, and git diff --check passed
简体中文

四条 finding 均确认成立并已修复:tar scanner 现在正确跨 chunk 跳过 payload;crash retry 会识别并续接同一 staged target;现有 authority lease 已继续继承到真正的 target Candidate,launch owner 异常退出时先关闭 Host 再释放 lease;PAX、GNU sparse/long-name 等会改写 tar 语义的扩展在两处 npm extraction 前统一拒绝。

PR 已 rebase 到当前 main,冲突解决时保留了主线新增的 managed activation、managed launch claim 与共享 npm deployment-layout authority。终态双重审查未发现第二份 lock、journal、owner state 或可删除的重复机制。

Generated-by: Codex

@likun666661
likun666661 merged commit 98d3965 into apache:main Aug 28, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/XL Over 1000 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants