Use the reviewed placeholder-filesystem rule when storage health assesses structured Unraid state, while retaining explicit DISK_NP_MISSING members as critical evidence.
Change-source: pulse-maintainer
Contract-Neutral: Unraid fsType=auto placeholder normalization is applied consistently at storage-health assessment without changing contracts
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)
Backport the browser-only refresh proof corrections from main. Exercise the
always-present History tab, follow the Proxmox surface's source-scoped canonical
resource query, trigger the metadata refresh path, and await the completed
response before checking drawer and viewport stability.
Contract-Neutral: browser regression coverage only; no runtime or API change.
Change-source: pulse-maintainer
Backport-of: 07c2f9ffa0
Backport-of: cf5e363979
The browser compatibility coalescer could undo the server's provider-scoped split after websocket reconciliation. Honour machine and provider identity before merging same-hostname rows.
(cherry picked from commit 724a8a4960)
A cluster name is an operator-selected display label, not global machine identity. Two independently configured estates using the same label could share one linked agent and then collapse into one presentation row after delayed cluster detection. Require node identity, exact endpoint, or host corroboration across provider instances instead.
Refs #1753
Change-source: pulse-maintainer
(cherry picked from commit 384dc53608)
gopsutil defaults to PID 1's mount table, which differs from the namespace created for Pulse's hardened systemd service. Enumerate the collector's own mount table so explicitly included tmpfs and bind mounts are discoverable, while preserving deliberate host-proc overrides for container deployments.
Change-source: pulse-maintainer
(cherry picked from commit 9d5cdfa088)
The stable-row focus fallback ran after the shared dialog cleanup and could scroll a lower Manage trigger into view. Preserve the existing focus return without changing the operator's viewport, and cover the real desktop and narrow browser path.
Contract-Neutral: frontend focus-restoration bugfix; no API or persisted-data change.
Change-source: pulse-maintainer
(cherry picked from commit da9800ff2f)
Shared subtabs used scrollIntoView for horizontal visibility, allowing remounted or programmatically changed drawers to scroll the whole application shell. Reuse the horizontal rail controller instead, and restore disclosure focus without scrolling when a detail row closes.
Record the shared primitive contract and its registry-approved guardrails, with desktop and narrow Backups browser coverage for visible Overview and Manage states, off-screen tab changes, and non-scrolling focus return.
Change-source: pulse-maintainer
(cherry picked from commit 59e9f5ea2b)
Connection-ledger refreshes replaced the selected connection snapshot and re-ran the credential slot renderer, destroying unsaved form state despite the node-level dirty guard. Keep the editor owner bound to the selected source while allowing the surrounding live row and dialog description to refresh.
Regression coverage advances both lastSeen and the endpoint, proving the form mounts once and retains input while live context updates.
Contract-Neutral: frontend state-lifetime bugfix; no API or persisted-data change.
Change-source: pulse-maintainer
CORE 12 appliances can report versions such as TrueNAS-12.0-U5 without a CORE product marker, and they do not expose the JSON-RPC endpoint required by modern SCALE releases. The existing legacy check therefore rejected a supported REST-capable appliance before collection could begin.
Recognise the explicit TrueNAS 12 family while retaining the fail-closed boundary for modern releases, and cover negotiation with the reported version string.
Contract-Neutral: TrueNAS legacy-version negotiation fix; no wire, API, persisted-data, or subsystem contract change
Change-source: pulse-maintainer
Patrol's readiness probe against a GPT 5.6 Luna deployment on Azure AI
Foundry failed with "Unsupported parameter: 'max_tokens' is not supported
with this model. Use 'max_completion_tokens' instead." The provider only
switched fields for o1/o3/o4 models, and only on api.openai.com, so the
GPT-5 family was sent max_tokens everywhere and Azure hosts were treated
as generic OpenAI-compatible endpoints.
Treat the GPT-5 family as reasoning models on the official and Azure
OpenAI hosts. Because an Azure deployment name need not reveal the model,
also act on the API's own instruction: when a 400 names max_completion_
tokens, re-send once in that form, drop the non-default temperature those
models refuse, and remember the answer for the life of the client so later
requests, including Patrol's streaming probes, go straight out correctly.
Refs #1837
Contract-Neutral: OpenAI provider parameter selection fix for issue 1837; no wire, API, or subsystem contract change
The secure-runtime qualification required the candidate commit to be an
ancestor of origin/main. Under the release train a patch candidate is cut
from release/vX.Y and is not on main at all, so v6.4.3-rc.1's
qualification failed at "Verify detached release source" before running
any check, and the steward correctly refused to treat the candidate as
stable-capable. Resolve the branch the control plane maps the version to,
fetch that, check ancestry against it, and hand the same ref to the
attestation so the receipt records the line it was verified against.
Refs #1753
Contract-Neutral: release qualification checks ancestry against the mapped release branch; no product or contract change
(cherry picked from commit 79d87a4a2c)
de41ea1883 replaced the chart-version step's output echoes with
scripts/write_github_output.py, but that step runs before the repository
is checked out, so the script does not exist yet and the Helm publish
fails with "can't open file ... write_github_output.py" on every release.
The v6.4.3-rc.1 run 33580123246 hit it after all other staging succeeded.
Run the checkout first; nothing in it depends on the version outputs.
The v6.4.3-rc.1 dispatch from main (run 33579042375) failed inside the
compiler dispatch: main advanced one minute after the release pipeline
pinned its source SHA, so the exact-SHA identity check on the compiler run
correctly refused the moved head. With the maintainer landing pull requests
every few minutes, a candidate dispatched from main cannot hold its SHA for
the minutes between prepare and compile.
Declare release/v6.4 for the 6.4.3 version prefix, created from main at the
exact-SHA-qualified commit 56e51e622e, so the workflow refuses a v6.4.3
dispatch from any other branch and the compiler binding stays exact. This is
the delivery contract's branch-per-train rule applied to the patch line that
predates the first train; earlier 6.4.x versions keep their historical main
mapping, and the 6.5 train mapping is unchanged.
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.