Treat Unraid's fsType=auto value as a placeholder rather than disk assignment evidence at both agent collection and server ingestion boundaries. Preserve real assigned and explicit missing members.
Change-source: pulse-maintainer
Contract-Neutral: Unraid fsType=auto placeholder normalization fixes false missing-slot alerts without changing wire or subsystem contracts
(cherry picked from commit fd843da7dfc51bba29bb5ddcbcdb4480d0e67079)
(cherry picked from commit 7a6456969d)
Make the shared Dialog prop contract require exactly one accessible-name strategy so new modal call sites cannot silently omit screen-reader context. Record the canonical primitive contract, preserve existing runtime behavior, and cover both valid strategies plus invalid unnamed and ambiguous props.
Change-source: pulse-maintainer
Keyboard and screen-reader users could not reliably bypass the shell or identify two General Settings toggles, while the RC badge failed the maintained contrast contract. Restoring explicit focus transfer, accessible control names, and compliant badge contrast keeps core navigation and settings usable without changing product scope.
Change-source: pulse-maintainer
Contract-Neutral: Accessibility regression fix only; no public contract or subsystem boundary changes.
The Docker and Kubernetes retry tests used a whole-runtime timeout as both
their synchronization point and shutdown trigger. Under suite load, startup
could consume that deadline before the second module initialization, producing
a false failure unrelated to retry behavior.
Wait for the successful retry explicitly, then cancel and verify clean
shutdown so the tests measure the lifecycle contract deterministically.
Change-source: pulse-maintainer
Rootful evidence must reject non-running systemd states and prove no unrelated container runtime survives. Require exact manager state, mask distro containerd, recheck readiness after scenarios, and remove the complete Podman socket boundary.
The disposable host reached multi-user.target in a degraded state because distro Podman housekeeping used overlay storage inside the outer container. Mask unused units, force VFS for explicit daemons, and fail closed on systemd unit failures so retained rootful evidence remains trustworthy.
The pre-batch upstream rootful source-closure manifest was created before the local Unix recovery test. Include that compiled installer input so merged qualification evidence remains bound to the complete harness.
Change-source: pulse-maintainer
(cherry picked from commit f5ad4e343e)
A workflow dispatch by branch can resolve after that branch moves, allowing an unreviewed tip to enter the release pipeline. Require every publishing dispatch to name its expected source SHA and make the workflow reject a different source or workflow commit before checkout.
Change-source: pulse-maintainer
(cherry picked from commit a461fc9c0a)
The Unix agent-ID recovery test imported syscall.Mkfifo from a generic test file. Go must compile that file before its runtime skip can run, so Windows CI could no longer build the installer test package. Keep the security regression on supported Unix targets while restoring the Windows delivery signal.
Change-source: pulse-maintainer
(cherry picked from commit c0ca94ee9f)
(cherry picked from commit d2cc6b4884)
The transparency page told evaluators that routine changes may merge
without line-by-line review, but not what governs a landing or a
release, so the commit stream was the only evidence and it read badly
(discussion #1539, the release-reliability ledger entry). The page now
states the delivery contract in public terms: every writer lands through
a pull request that auto-merges on green required checks with no bypass,
the maintainer's pull requests carry outcome, reason, and validation, and
releases run on a train with a soaked, exact-content candidate, with the
rules in RELEASE_PROMOTION_POLICY.md. The shipped docs mirror is updated
with it.
The maintainer's candidate preflight already refuses a commit without a
body or with a subject over 72 characters. The new husky commit-msg hook
holds human and interactive-agent commits in this checkout to the same
standard, exempting merge, fixup, squash, and revert messages.
Stable promotions built whatever the dispatch branch was at that second.
The resolver checked that HEAD descends from the promoted release
candidate but never that its content matches, so v6.4.0 shipped 64
changed files, including product code, that v6.4.0-rc.12 had not
soaked. Every v6 version was mapped to main, which now moves every few
minutes under the autonomous maintainer, so each fix to a candidate
brought everything landed since and stable was never an exact soaked
commit. Five of six stable minor releases shipped under version-bound
owner exceptions that waived the soak.
From v6.5.0 the release train applies (RELEASE_PROMOTION_POLICY.md,
"Release Train"): a two-week train sized to measured velocity, a
release/v6.N branch per train declared in the control plane so the
workflow refuses a dispatch from anywhere else, a stable promotion that
may differ from its candidate only in release metadata unless
hotfix_exception names active customer harm, and a seven day soak for
minor releases. The 6.4.x line stays on main so the v6.4.3-rc.1
candidate already prepared there is unaffected. The gap is registered
as coverage gap release-train-exact-candidate-promotion.
A paying operator asked the Assistant to reboot five Proxmox VMs matching
a name pattern (GitHub #1782, support mail 2026-08-26 and 2026-08-29). The
model resolved the VMs and then ended with a report that invented a
prerequisite: a QEMU guest agent on 6.3.2, a "discovery binding" on stable
6.4.0. It never planned the action. Three defects made the governed path
fail whenever the model did try it, and nothing refused the prose ending
when it did not:
- pulse_control handed the session-scoped id (vm:<node>:<vmid>) to the
action lifecycle, whose registry keys on canonical unified ids, so a
Proxmox guest plan could never resolve.
- pulse_control gated the action on the legacy per-executor action list,
which never carried the canonical "reboot" capability Proxmox guests
advertise, so "reboot" was refused as not permitted before planning.
- A reference absent from the session context was refused with "resource
discovery is required" even when the unified inventory resolved it.
pulse_control now binds its target to the canonical unified resource
(session alias first, then a unique inventory match, refusing ambiguity
with candidate ids and naming the pulse_query recovery on a miss), passes
the canonical id to the planner, and answers "not available" only from
the resource's current advertised capabilities. The FSM ordering block
and the shared operating instructions state that a recoverable block is
not a limitation to report, and the instructions require the governed
action tool for advertised capabilities. The agentic loop adds a bounded
advertised-action gate: when the operator asked for a lifecycle action,
pulse_control was offered but never submitted, and a session-resolved
resource advertises the action, a tool-free final answer is refused once
with the exact per-target calls.
Covered by tools and loop unit tests (the #1782 transcript against a
scripted provider fails on the previous code with the two exact errors
above), a prompt-contract test, and the live eval scenario
ProxmoxBulkLifecycleActionScenario.
Since 60d0651a88 every typed request registers a per-connection cancellable
slot that its handler goroutine releases in a deferred cleanup after sending
its result. The server replays a request id when it wants the durable receipt
again, and that replay can reach the reader before the previous handler's
deferred release runs. launchCancellableRequest treated that as a duplicate
and dropped it, so the server waited out the operation's full timeout for a
result the agent already held. The Linux x64 native-verification leg failed
this way on 12 of the last 25 main runs, always on a "replay 1" dispatch of
host update, storage cleanup, or Docker lifecycle.
Give each slot a done channel that closes on release. A replay whose id is
still registered on the same connection now waits for that release and then
runs, answering from the durable receipt. Invalid ids and over-capacity
requests are still dropped. A unit test pins the wait-then-run behaviour and
the agent-lifecycle contract records the replay rule.
agent_state_dir_lifecycle_test.go calls syscall.Mkfifo, which does not
exist on Windows, so scripts/installtests has failed to compile in the
Windows leg of Unified Agent Native Verification since 53267e149d and the
install.ps1 contract tests there have not run. Every test in the file
drives install.sh through bash and systemd, so tag the file unix-only,
matching the other lifecycle lab files. GOOS=windows go vet now passes.
The cancellation replay test stopped the first action runner and started a
second one as soon as the client goroutine exited. The server observes the
socket close on its own reader, so under GOMAXPROCS=1 with the race detector
the second startRunner saw the stale session as still connected and the
replay was dispatched to the dead socket, timing out after 30s on the
sharded release preflight while passing on multi-core hosts. Wait until the
server reports the agent disconnected before reconnecting, as the agentexec
server tests already do.
go test places t.TempDir under GOTMPDIR, and the preflight worker nested that
under its per-run directory, so unix socket fixtures in cmd/pulse-agent-helper,
internal/agenthelper, and internal/dockeragent exceeded the 108-byte sun_path
limit and failed with "bind: invalid argument". GitHub runners leave GOTMPDIR
unset, and the longest rootless Podman fixture sits exactly at the limit under
/tmp, so the worker now leaves GOTMPDIR unset by default and only honours an
explicit PULSE_RELEASE_PREFLIGHT_GO_TMP_DIR override.
Two cmd/pulse-agent helper tests ran without a state directory, so the agent
consulted the platform default /var/lib/pulse-agent. On a host where that
path exists as a private directory the pending-update handoff lookup fails
with permission denied. Give those tests an isolated state directory.
install.sh refuses connection state, token, and lifecycle files whose
parent directory is group- or world-writable. The fixtures build those
parents with t.TempDir, which inherits the process umask, so on a worker
with umask 002 the state directory came out 775 and seven TestInstallSH
cases failed on the pulse-dev release preflight while passing on GitHub
runners and macOS. Set umask 022 for the package on unix so the tests
prove the installer contract rather than the host's umask.
Recognize bare sequence entries and every valid block scalar header across executable action inputs, run scripts, and step environment boundaries.
Change-source: pulse-maintainer
The exact-SHA preflight streams the worker script over a non-login ssh
shell, so /etc/profile.d/mise.sh is never sourced and a stale system Node
binary on the worker shadows the infra-managed mise toolchain. pulse-dev
carried a manually installed Node 20 symlink in /usr/local/bin, so the
worker failed its Node 24 check while a login shell resolved 24.19.0.
Activate mise shims when mise is installed so the worker uses the same
toolchain the bootstrap provisions, regardless of how it is invoked.
Open the v6.4.3 candidate line from main. The v6.4.2 tag was staged on
2026-08-31 but never activated: its release run was cancelled after the
private Pro build failed the compiler memory gate, so the latest published
stable is still v6.4.1. This candidate carries the complete v6.4.2 change
set plus the corrections landed since that tag, including the stale PBS
Backup Running state (#1815), the Windows Unified Agent auto-update 404
(#1820), and shared-token same-hostname agent identity collapse (#1753).
Packet: VERSION, compose and install-docker defaults, Helm chart metadata,
release notes with a declined visual plan, changelog, pointer docs and
the shipped docs mirror, and the deployment-installability cutoff note.
Rollback target is v6.4.1 and the mobile decision is no-mobile-impact.
Tests: the packet tests now describe the 6.4.3 train, v6.4.2 is recorded
as an unpublished stable so it is never derived as the previous stable or
rollback target, and the Python v6.4.2 notes expectation matches the
phrase the notes actually use.