feat(native): durable external-owner updates, CLI, admin command and opt-in automation #340

Open
karsten wants to merge 7 commits from feat/native-update-surface into main
Owner

Operator scope

Native non-immutable-container Hayate updates: product CLI, authenticated admin request, opt-in automatic discovery, and a durable external OS-user owner. Not an external release-publisher fix. No merge or live activation is requested from this worker.

Product changes

  • hayate-agent update [check|status|update|automatic] and no-argument admin /update-restart persist deterministic singleton requests before acknowledgement; no in-process self-restart or model-supplied shell/path.
  • Explicit private managed-root/home/service/variant binding; public existing Forgejo release/OCI digest provenance and integrity; reject immutable containers/unsupported platforms.
  • Product-owned Linux x86-64 systemd-user Python owner, reusing reconciler/bootstrap/launcher/payload/runtime design, not machine-private paths. Fresh admission, same process/unit/cgroup validation, SIGTERM-only drain, atomic sealed selection, exact revision health, rollback and journal recovery.
  • Stable packaged owner modules, inert installer, user service/timer artifacts. Installer copies only; it never enables, starts, adopts, changes bindings or reads credentials. Opt-in scheduler has persisted slots and terminal receipts, no fixed-version hold.
  • Docs: docs/native-update.md, native/README.md, and docs/native-update-handoff.md cover actual commands/config, refusal behavior, default unit paths and explicit parent deployment gates.
  • PR-only scoped CI uses the existing validation-runner pattern for exact-head full typecheck/build/tests plus real-Node qualification and installer dry-run. No publishing/rollout workflow, credentials or production service access.

Evidence (isolated clone, not deployment)

  • Full local typecheck and build passed after clearing inherited runtime library environment.
  • Python owner tests: 98 passed, including installer CLI dry-run/read-only assertion, byte-identical inert installation, modes, symlink/permission/existing-install refusal, external-process lifecycle and rollback/recovery.
  • Real Node/bundled ELF-loader qualification: 1 passed, including invalid JavaScript refusal.
  • Actual installer --dry-run returned ten-file plan with activation: false; target remained absent.
  • Full local test set with CI-equivalent concurrency=4: 1877 passed, 0 failed, 1 skipped (1878 total). An earlier unbounded local run had three subprocess timeout failures; no tests were excluded. Normal umask 0022 cleared the baseline API-credential fixture failure, and native private-home fixture now explicitly uses 0700.
  • Initial CI identified runner portability defects in the test fixtures, now corrected: Node resolved via PATH, ELF binutils included in both full-validation images, synthetic native host isolated in test-only preload/supervisor fixture. Production refusal is unchanged and directly tested before fixture installation. Exact-head CI remains a gate; see current status below.

Required review / deploy handoff

Review admission races and recovery, protected path/receipt handling, extraction/ELF closure, unit/identity fencing, acknowledgement-before-exit and nonstandard variant compatibility. Home/config/crypto/credentials/productive queues/pending approvals/native MCP/local TUI are not migration inputs and must pass target acceptance. Fixture tests are not published OCI, real systemd or local-variant acceptance.

Parent retains merge and external-owner installation/activation after normal CI and scoped independent review. Initial adoption/rollback qualification and the actual unit binding are a separate supervised OS-owner transaction. Automatic discovery stays disabled until that acceptance. No agent process was signaled, restarted or updated; no live units/timers were installed or enabled. Dirty operator workspace and paused historical worker ledgers were not touched.

Exact-head CI verified

At e11756e0c4c09200045e922fa4d6f47669fda54d, both checks are green:

Merge, independent parent review, deployment acceptance and external-owner activation remain outstanding. No running agent was updated or restarted.

## Operator scope Native non-immutable-container Hayate updates: product CLI, authenticated admin request, opt-in automatic discovery, and a durable external OS-user owner. **Not an external release-publisher fix. No merge or live activation is requested from this worker.** ## Product changes - `hayate-agent update [check|status|update|automatic]` and no-argument admin `/update-restart` persist deterministic singleton requests before acknowledgement; no in-process self-restart or model-supplied shell/path. - Explicit private managed-root/home/service/variant binding; public existing Forgejo release/OCI digest provenance and integrity; reject immutable containers/unsupported platforms. - Product-owned Linux x86-64 systemd-user Python owner, reusing reconciler/bootstrap/launcher/payload/runtime design, not machine-private paths. Fresh admission, same process/unit/cgroup validation, SIGTERM-only drain, atomic sealed selection, exact revision health, rollback and journal recovery. - Stable packaged owner modules, inert installer, user service/timer artifacts. Installer copies only; it never enables, starts, adopts, changes bindings or reads credentials. Opt-in scheduler has persisted slots and terminal receipts, no fixed-version hold. - Docs: `docs/native-update.md`, `native/README.md`, and `docs/native-update-handoff.md` cover actual commands/config, refusal behavior, default unit paths and explicit parent deployment gates. - PR-only scoped CI uses the existing validation-runner pattern for exact-head full typecheck/build/tests plus real-Node qualification and installer dry-run. No publishing/rollout workflow, credentials or production service access. ## Evidence (isolated clone, not deployment) - Full local typecheck and build passed after clearing inherited runtime library environment. - Python owner tests: 98 passed, including installer CLI dry-run/read-only assertion, byte-identical inert installation, modes, symlink/permission/existing-install refusal, external-process lifecycle and rollback/recovery. - Real Node/bundled ELF-loader qualification: 1 passed, including invalid JavaScript refusal. - Actual installer `--dry-run` returned ten-file plan with `activation: false`; target remained absent. - Full local test set with CI-equivalent concurrency=4: **1877 passed, 0 failed, 1 skipped (1878 total)**. An earlier unbounded local run had three subprocess timeout failures; no tests were excluded. Normal umask 0022 cleared the baseline API-credential fixture failure, and native private-home fixture now explicitly uses 0700. - Initial CI identified runner portability defects in the test fixtures, now corrected: Node resolved via PATH, ELF binutils included in both full-validation images, synthetic native host isolated in test-only preload/supervisor fixture. Production refusal is unchanged and directly tested before fixture installation. Exact-head CI remains a gate; see current status below. ## Required review / deploy handoff Review admission races and recovery, protected path/receipt handling, extraction/ELF closure, unit/identity fencing, acknowledgement-before-exit and nonstandard variant compatibility. Home/config/crypto/credentials/productive queues/pending approvals/native MCP/local TUI are not migration inputs and must pass target acceptance. Fixture tests are not published OCI, real systemd or local-variant acceptance. Parent retains merge and external-owner installation/activation after normal CI and scoped independent review. Initial adoption/rollback qualification and the actual unit binding are a separate supervised OS-owner transaction. Automatic discovery stays disabled until that acceptance. No agent process was signaled, restarted or updated; no live units/timers were installed or enabled. Dirty operator workspace and paused historical worker ledgers were not touched. ## Exact-head CI verified At `e11756e0c4c09200045e922fa4d6f47669fda54d`, both checks are green: - [native-update-ci / full-validation](https://git.vanillacore.net/harness/core/actions/runs/32/jobs/0): full typecheck/build/test set, real Node qualification and installer dry-run. - [decision-interface-ci / full-validation](https://git.vanillacore.net/harness/core/actions/runs/31/jobs/0): full typecheck/build/test set. Merge, independent parent review, deployment acceptance and external-owner activation remain outstanding. No running agent was updated or restarted.
test(native): isolate native fixtures from container CI and resolve Node via PATH
Some checks failed
decision-interface-ci / full-validation (pull_request) Failing after 2m7s
native-update-ci / full-validation (pull_request) Failing after 2m8s
fe45cdcf83
test(native): qualify supervisor fixture on container runners with ELF tools
All checks were successful
decision-interface-ci / full-validation (pull_request) Successful in 2m13s
native-update-ci / full-validation (pull_request) Successful in 2m10s
e11756e0c4
All checks were successful
decision-interface-ci / full-validation (pull_request) Successful in 2m13s
native-update-ci / full-validation (pull_request) Successful in 2m10s
This pull request has changes conflicting with the target branch.
  • src/commands.ts
  • src/launcher.ts
View command line instructions

Manual merge helper

Use this merge commit message when completing the merge manually.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/native-update-surface:feat/native-update-surface
git switch feat/native-update-surface
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
harness/core!340
No description provided.