Record fresh offline Chromium evidence for the exact merged web source at 2606c9d36a. The per-commit browser guard requires that verified parent, not the earlier assigned candidate base. Preserve the original protected merges and setup assertion without replaying the UI proof.
Change-source: pulse-maintainer
Compose protected Pulse PRs #2312 and #2313 with the reviewed main candidate so first-source setup guidance, the corrected E2E assertion, and later repairs can be verified together. Browser proof for the composed source follows in a separate receipt commit.
Change-source: pulse-maintainer
With AI switched off the empty Actions inbox still said "Patrol runs in
Watch only mode" and pitched Pulse Pro modes, because the autonomy
setting reads as monitor even when Patrol is not running at all. That
tells an AI-off user something untrue and turns an empty page into an
upsell for a feature they turned off (issue #905).
The guidance now requires the same assistantEnabled session capability
that gates the Assistant launcher and the Patrol navigation, and falls
back to the plain empty-state copy otherwise.
Stacked on #2312; once that lands only this commit remains.
Issue #905 asked for every AI entry point to disappear when AI is
switched off, and the Assistant launcher still honours that through the
assistantEnabled session capability. Patrol did not: v6 added it as a
permanent top-level tab, mobile bottom-bar slot, g r shortcut and
command-palette entry, and the palette also kept offering Assistant
commands. Patrol cannot run without a configured provider, so an AI-off
install carried a tab that only led to an "off" page.
Gate all of those on the same capability as the Assistant launcher.
Settings keeps its Patrol and Assistant items and /patrol stays
reachable, so the path back to turning AI on is unchanged.
Also rename the System settings item "Pulse server updates" to
"Updates" and drop "runtime" from its description. The item already sits
in the System group, and the description still sends agent updates to
Infrastructure, which was the reason for the longer name.
With AI switched off the empty Actions inbox still said "Patrol runs in
Watch only mode" and pitched Pulse Pro modes, because the autonomy
setting reads as monitor even when Patrol is not running at all. That
tells an AI-off user something untrue and turns an empty page into an
upsell for a feature they turned off (issue #905).
The guidance now requires the same assistantEnabled session capability
that gates the Assistant launcher and the Patrol navigation, and falls
back to the plain empty-state copy otherwise.
Issue #905 asked for every AI entry point to disappear when AI is
switched off, and the Assistant launcher still honours that through the
assistantEnabled session capability. Patrol did not: v6 added it as a
permanent top-level tab, mobile bottom-bar slot, g r shortcut and
command-palette entry, and the palette also kept offering Assistant
commands. Patrol cannot run without a configured provider, so an AI-off
install carried a tab that only led to an "off" page.
Gate all of those on the same capability as the Assistant launcher.
Settings keeps its Patrol and Assistant items and /patrol stays
reachable, so the path back to turning AI on is unchanged.
Also rename the System settings item "Pulse server updates" to
"Updates" and drop "runtime" from its description. The item already sits
in the System group, and the description still sends agent updates to
Infrastructure, which was the reason for the longer name.
An existing cpu_thermal chip with an unusable CPU value can still carry valid fan readings. Use a free synthetic CPU-chip key instead of replacing that entry when supplementing Pulse #2311, and cover the collision with a regression test.
Change-source: pulse-maintainer
Dispatch the post-publication check from protected main while binding its packet to the immutable RC tag. Accept only canonical Pulse checkout origins before normalising the spelling required by the attester, and document the deployment contract and source guard together.
Change-source: pulse-maintainer
A named CPU chip with no valid CPU temperature must not suppress an identified SoC thermal reading. Preserve other lm-sensors readings and existing valid CPU precedence.
Change-source: pulse-maintainer
When lm-sensors returns disk or other readings without a CPU chip, retain those readings and add a bounded, identified SoC temperature from sysfs. Preserve existing CPU output and ignore unusable optional sysfs data. Cover combined and precedence paths for Pulse #2311.
Change-source: pulse-maintainer
Fall back to bounded, type-checked thermal-zone and hwmon sysfs readings when lm-sensors is absent or empty. Classify Armada thermal JSON as a CPU reading, preserve nonempty sensor output, and cover units, invalid values, and the agent mapping.
Change-source: pulse-maintainer
The main first-source wording changed in #2309, but the integration test still required the superseded sentence. Assert the reviewed host/API distinction while retaining the existing infrastructure navigation checks.
Change-source: pulse-maintainer
Recognise exact node.VMID.name notes on Root PBS snapshots so a newer completed CT backup can replace an older name-only match. Keep colliding VMIDs fail-closed when node and name do not distinguish connections, and cover completed and in-flight attribution for Pulse #2292.
Contract-Neutral: Preserve backup attribution safety without changing API fields, persisted shapes, or source contracts.
Change-source: pulse-maintainer
## What changed
Correct the first-source setup screen so API connections, agent
installation, and optional host-local temperature/SMART coverage are
described accurately in English, German and Spanish. The guidance no
longer promises sensors on every Proxmox host. Installer behaviour and
sensor support are unchanged.
## Why
The wording introduced with first-source setup (#2303) could lead users
to expect sensor readings that depend on their platform and hardware.
This is a copy-only correction to that user-facing guidance.
## Included source
Reviewed commits `ab4f04da3d67d20c51943666be9bf4515ebb3b3f` through
`2e428460eedea66e72c5291383c961847e4d3b42`, after published main
`4de772658b338d5ddca9bf7012b4b7f220edde88`.
## Validation
The exact reviewed head passed offline `npm ci`, type-check, lint, the
full frontend test suite and production build (source proof
`source-erujaq9i`). Twelve Chromium locale, data-state and viewport
previews passed without page errors or horizontal overflow. The range
passed metadata provenance and diff checks. Protected exact-head PR
checks remain required before landing; this does not imply a release.
[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
The API-connected next step and combined-source option still implied that installing a Proxmox agent always supplies temperature and SMART readings. Describe them as host-local telemetry only where available in English, German and Spanish, cover both states in tests, and bind twelve rendered locale/viewport states.
Contract-Neutral: Copy-only clarification of conditional sensor coverage; installer behaviour, sensor support and credential scopes are unchanged.
Change-source: pulse-maintainer
Make the setup-completion guidance explain that users run the host installer
and that sensor and workload coverage varies by platform. Align English,
German and Spanish copy, update coverage tests, and bind a rendered desktop
and narrow-browser receipt.
Contract-Neutral: Correct misleading first-source copy only; installer behaviour, sensor support and credential scopes are unchanged.
Change-source: pulse-maintainer
The resolver refused a stable promotion until its candidate had soaked
for 72 hours, or 168 for a minor. Few installs run previews: 35 of about
7,900 active installs ran v6.4.5-rc.3 in the week to 2026-09-28, while
75 percent sat on a month-old stable. The minimums drop to 24 hours for
minor and patch alike; the content-drift check and the hotfix exception
are unchanged. The workflow and trigger prompts, the promotion policy
and the deployment-installability contract say the same.
After security setup, the screen asked new users to choose "how the
first
system should enter the unified infrastructure model: platform API
inventory, Pulse Agent telemetry, or both", under a "Choose the first
source strategy" heading. Someone who only wants their Proxmox server on
screen knows none of those terms, and this is where most never-activated
installs stop: in the week to 2026-09-28, 280 of 596 persistent installs
that never monitored anything had finished security setup and then never
configured a connection.
The screen keeps its structure and routing. The copy now says what to
do and what each path shows: connect Proxmox, TrueNAS or VMware by API
with nothing to install, add the agent for temperatures, disk health and
Docker, or both. German and Spanish follow, and the agent-lifecycle
contract records the plain-words rule.
Contract-Neutral: copy-only: plain-language first-source setup copy;
owning agent-lifecycle clause updated; no runtime, API or primitive
change
## What and why
Stabilise agent update-readiness and monitoring history-window tests
without weakening their assertions. The failed v6.4.5-rc.4 exact
preflight (packet 20260928T080527Z-release) exposed timing-sensitive
failures that could block the #2282 updater repair from reaching a
qualified release. This main-line batch also incorporates the
already-published dropped-session dispatch repair from Pulse #2300 and
container-console setup guidance from #2302 without rewriting either
reviewed test commit.
## Included range
Pulse `main`
`75c72ef505b24e31214162b7b46f97e357528ae3..cbb9122bcc216e335867fa4fed98c4451b12bd27`:
reviewed test candidates `bc3a7306` and `383e05ae`, followed by additive
upstream integrations `894d7409` and `cbb9122b` (published main
`ad15366f`).
## Validation
Provenance, clean-tree and diff checks passed. Committed-source offline
race proof `source-_ki_8c7c` passed the named failure tests for 20
repetitions. The composed v6.4 counterpart passed the full affected
packages with race detection (`source-7g64cyz2`). Exact-head GitHub
checks remain required before merge; source tests do not qualify or
publish v6.4.5.
[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
The resolver refused a stable promotion until its candidate had soaked for
72 hours, or 168 for a minor. Few installs run previews: 35 of about 7,900
active installs ran v6.4.5-rc.3 in the week to 2026-09-28, so a longer
soak saw little the first day did not, while 75 percent of installs sat on
a stable build a month old. Richard set a 24 hour soak for every release
on 2026-09-28.
The minimums drop to 24 hours for minor and patch alike, the error text
reads the constants instead of repeating numbers, and the workflow and
trigger prompts, the promotion policy and the deployment contract say the
same. The content-drift check and the hotfix exception are unchanged.
The first rewrite told users that Proxmox, TrueNAS and VMware need
nothing installed, which reads as "do not put the agent on them". On
Proxmox that is wrong: the API does not report node temperatures or SMART
disk health, and the agent on each node does. TrueNAS already reports
both through its API, and ESXi hosts take no agent, so the copy now says
to start with the API and add the agent on Proxmox nodes.
Contract-Neutral: copy-only: correct first-source copy about the agent on Proxmox nodes; no runtime, API or primitive change
After security setup, the screen asked new users to choose "how the first
system should enter the unified infrastructure model: platform API
inventory, Pulse Agent telemetry, or both", under a "Choose the first
source strategy" heading. Someone who only wants their Proxmox server on
screen knows none of those terms, and this is where most never-activated
installs stop: in the week to 2026-09-28, 280 of 596 persistent installs
that never monitored anything had finished security setup and then never
configured a connection.
The screen keeps its structure and routing. The copy now says what to
do and what each path shows: connect Proxmox, TrueNAS or VMware by API
with nothing to install, add the agent for temperatures, disk health and
Docker, or both. German and Spanish follow, and the agent-lifecycle
contract records the plain-words rule.
Contract-Neutral: copy-only: plain-language first-source setup copy; owning agent-lifecycle clause updated; no runtime, API or primitive change
The unlock screen told Docker users to run `docker exec` from the host,
which does not fit the Unraid, Portainer and TrueNAS app UIs, where the
console already runs inside the container. Those `container_other`
installs are the largest group stalling before first setup: in the week
to 2026-09-28, 158 of 3114 persistent Docker installs never got past
first start, against 94 of 5462 binary and systemd installs.
The startup log also suggested revealing the token "by reading the token
file path". That file holds ciphertext, as the security-privacy contract
requires, so anyone following the hint pasted JSON the unlock screen
rejects. The log now names the command, including the console form, and
the install docs and the contract gain the same guidance.
Contract-Neutral: copy-only: new unlock-screen command row and corrected
startup log text; no API payload, lifecycle, storage or primitive
change; owning security-privacy clause updated
The unlock screen told Docker users to run `docker exec` from the host,
which does not fit the Unraid, Portainer and TrueNAS app UIs, where the
console already runs inside the container. Those `container_other`
installs are the largest group stalling before first setup: in the week
to 2026-09-28, 158 of 3114 persistent Docker installs never got past
first start, against 94 of 5462 binary and systemd installs.
The startup log also suggested revealing the token "by reading the token
file path". That file holds ciphertext, as the security-privacy contract
requires, so anyone following the hint pasted JSON the unlock screen
rejects. The log now names the command, including the console form, and
the install docs and the contract gain the same guidance.
Contract-Neutral: copy-only: new unlock-screen command row and corrected startup log text; no API payload, lifecycle, storage or primitive change; owning security-privacy clause updated
The supervisor sends its commit call before returning, but both channels can be ready when the test wakes. Treat a completed successful supervisor with the recorded commit as success, and bound the post-commit wait.
Change-source: pulse-maintainer
The agentexec read loop removed a dead session from the agent map but never
closed its done channel, so any dispatch already sent on that session kept
waiting for a result that could never arrive and only returned at its
operation timeout. That's what made the Proxmox cancellation replay test
flaky on the shared CI runner. The restarted action runner dropped its first
session right after registering, the replay had already been sent there,
and the server waited the full 30s while the runner sat reconnected on a
new session.
The read loop now signals the session done on exit, so in-flight typed
dispatches and commands report the disconnect straight away. The
integration test sends the same request again on the runner's next
session when that happens, which is the same durable replay it is there
to prove, still with exactly one mutation. It also keeps the runner's log
and prints it on failure so the cause of any future drop is visible.
Wait for the agent supervisor to check false readiness before asserting its commit gate, and give the race-instrumented fixture a non-expiring window. Hold the monitoring request at target resolution after its history snapshot so replacement is deterministic. Keep production paths and assertions unchanged.
Change-source: pulse-maintainer
TestCheckForUpdatesWithChannel_AvailableUsesCache and
TestCheckForUpdates_Wrapper hard-code a linux-amd64 archive, and since
ab0aa1ef0 the update check only offers an update when the exact archive
for the host architecture exists. CI runs on amd64 so it's green, but
both fail on arm64 machines. The fixtures now build the archive name
from the same runtime helper the updater uses. Test only.
This first went up to also fix the rest-1 failure from the #2286 test,
but 3a362f0af fixed that on main in the meantime, so I merged main and
kept its version. The internal/updates suite passes here on arm64 and on
amd64 through Rosetta. The v6.4 counterpart is #2296.
TestInstallSHRecoversV5ProcessArgsWithoutProcfs failed on #2297 in
Backend tests rest-1 with NOT_READY and an empty URL, and it passes
every time on a Mac. The test stubs the running agent as pid 4242 and
stubs ps, but running_agent_arg_stream reads /proc/<pid>/cmdline
whenever that exists and only falls back to ps when it doesn't. So on a
Linux runner where 4242 happens to be some other live process, it parses
that process's arguments instead of the stub and recovers nothing. macOS
has no /proc so it always takes the ps path.
The test now wraps the real function so it always resolves against an
empty proc root, which is the no-procfs host it's meant to describe, and
the real ps fallback still gets exercised. I reproduced the failure by
planting an unrelated 4242 cmdline in that root and the test fails with
NOT_READY as expected, then passes without it. Two smaller things while
I was in there. It was calling recover_connection_state_from_env_stream
without extracting it, which is where the command not found line in the
CI log came from, so that's extracted now. And the READY check could
never fail because READY is a substring of NOT_READY, so it checks
NOT_READY directly.
Test only. The full scripts/installtests package passes locally.
TestInstallSHRecoversV5ProcessArgsWithoutProcfs stubs the running agent
as pid 4242 and stubs ps, but running_agent_arg_stream reads
/proc/<pid>/cmdline whenever it exists and only falls back to ps when it
does not. On a Linux runner where pid 4242 happened to belong to another
process, recovery parsed that process's arguments and the test failed
with NOT_READY (seen in Backend tests rest-1). It never failed on macOS,
which has no /proc.
Wrap the real function so this test always resolves against an empty
proc root, which is the no-procfs host it describes. Also extract the
env-stream helper it was calling without, and fail on NOT_READY directly
since "READY" is a substring of it and never caught a failed recovery.
TestInstallSHRecoversV5ProcessArgsWithoutProcfs failed once in Backend
tests (rest-1) with "recover_connection_state_from_env_stream: command
not found". This branch changes no scripts, the test passes repeatedly
locally on the same tree, and main passes rest-1 at the merged base.
## What changed and why
- Make update-check telemetry describe an installable offer, rather than
treating release metadata without this binary's archive as an available
update (#2285). This also addresses the update-observation assertions
that failed in the prior protected-main Build and Test run.
- Choose newer PBS snapshots only when the guest can be uniquely
attributed, avoiding misleading VM/CT backup ages and cross-cluster
matches (#2292).
- Retain the first-seen age of a continuously observed Docker update
alert through cleanup, so its delay does not restart each day (#2048).
This proposal contains the reviewed local range
`c941a1165abbc793246f431939c94111727bc2a5..f7a43d27946a48a61b3c84a5bd1ab1fc561eab97`,
including the update-observation correction
`3a362f0afba30cf2527f27b3f87e2324559a920a`, the final tie-safe PBS
correction `d704afa68abeca49699f890f9fa81196f55084ab`, and Docker alert
correction `f7a43d27946a48a61b3c84a5bd1ab1fc561eab97`. Reviewed commit
identities are unchanged.
## Validation
Committed-source focused Go proofs passed for update/telemetry, PBS
model/monitoring attribution, and Docker alert handling (including the
alert race and full alert package checks). The candidate's range diff
check and publication provenance check passed. The earlier
protected-base `Build and Test` failure was inspected; it is not claimed
as a pass. This proposal still needs independent source review and
exact-head PR checks. Source placement is not a released or installed
fix.
[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
Main is failing Backend tests (rest-1) on
TestIssue2285LastUpdateCheckRecordsEffectiveChannelOutcome. The exact
server archive rule (ab0aa1ef0) offers an update only when the release
carries the archive for the host architecture, and the #2285 test
releases carried no assets, so its update-offered cases could never
report available. The two check tests also hard-coded a linux-amd64
archive, which failed on arm64 hosts.
Build every fixture archive from the same runtime asset helper the
updater uses. Test only.
Hourly cleanup previously aged pending image updates by first detection, so a continuing update older than 24 hours lost its tracking and could restart its delay. Track observation activity separately, keep unknown checks pending, and reclaim state when observations stop or an affirmative clear arrives. Cover 24- and 48-hour delays and cleanup.
Contract-Neutral: Preserve the existing Docker update alert policy and public contract while correcting internal tracking expiry.
Change-source: pulse-maintainer
A globally observed second cluster can leave a PBS source apparently mapped to the first while both clusters match a shared-node snapshot. Do not promote a positive but tied guest match into the VMID-only inference path. Regression covers both VM and CT completed and in-flight snapshots with the second cluster visible on another PBS instance.
Contract-Neutral: Preserve existing PBS backup attribution safety without changing API fields, persisted shapes, or source contracts.
Change-source: pulse-maintainer
A newer snapshot from another cluster can share the same typed VMID and node namespace. Compare each positive match with competing guests before selecting by recency; a stronger competitor excludes it and a tie needs independent attribution. Cover VM and CT completed and in-flight snapshots while preserving the newer weaker unique match.
Contract-Neutral: Repair existing backup badge attribution and age selection without changing API fields, persisted shapes, or PBS source contracts.
Change-source: pulse-maintainer
A stronger namespace or comment score currently makes an old snapshot beat a newer, still attributable snapshot. Keep the existing typed-VMID and cross-instance eligibility guards, then choose the latest eligible backup for LastBackup and in-flight state. Add VM and CT regressions for unique fallback and colliding IDs.
Contract-Neutral: Repair existing backup-age selection without changing API fields, persisted shapes, or PBS attribution eligibility.
Change-source: pulse-maintainer
## What changed and why
Keep queued notifications from being cancelled while saved destinations
load, and make stable-channel update discovery work with GitHub's large,
prerelease-heavy release list (#2282). Update download selection now
requires the exact server archive for the runtime architecture; ARMv6
and ARMv7 are distinguished by the build variant rather than silently
choosing ARMv7. The batch also retains the reviewed disk-monitoring
round-trip correction.
## Reviewed source
`b1e75fb9e4693c5706b2242760d6277e5291e7f9..18f2dc1f19416bd83ab72e7f82f2287063b0bedc`
(notification test isolation and startup gate, integration of update
metadata, exact-archive selection, ARM variant correction).
## Validation
Provenance and diff checks passed for the complete range. Prior
committed-source offline proofs passed for the update package through
`ab0aa1ef02698f7727b134a6f6b5ed520930cc61` and for the notification
startup race scenario. The new ARM mapping has a focused regression test
in this head; exact-head protected CI remains required before landing.
These source checks do not establish installed update or alert-delivery
results, nor release readiness.
[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
Combine the protected schema-v18 sender with the exact-archive updater. Require installable archives in positive fixtures, classify missing archives and unavailable Pro checks without claiming an offer, and avoid caching an unactivated Pro result. Record the contract and exact combined-source browser receipt.
Change-source: pulse-maintainer
Combine the reviewed main-line sender with the in-flight archive correction so the interaction can be repaired and proved at exact source.
Change-source: pulse-maintainer
This fixes#2285. A failed update check never shows up in the update
counters because nothing gets applied, so telemetry couldn't tell an
install whose check is broken from one that was offered an update and
ignored it. That's how the 6.4.3-rc.1 installs looked fine while their
check failed on every call.
The update manager now keeps a small record of the last check on the
install's own channel, just a fixed outcome like up_to_date, available,
no_release, rate_limited, network_error, metadata_error, skipped or
error, plus whether an update was offered. Lookup failures get tagged
with their category without changing the error text people see, and
previewing the other channel from Settings doesn't overwrite it.
Telemetry schema 18 sends that as update_channel, update_check_outcome
and update_available, and nothing else leaves the install, no versions,
URLs or error text.
The Settings preview type, the privacy page, the adoption report and the
subsystem contracts are updated to match. The receiver side is in the
pulse-pro repo and the schema parity check passes against it. Old
receivers just drop the new fields, so the two can deploy in either
order.
A failed update check never reaches the update history, because nothing
was applied, so telemetry could not tell an install whose check is broken
from one that was offered an update and ignored it. The 6.4.3-rc.1 installs
looked healthy while their check failed on every call (#2282).
The update manager now records a closed outcome for every check on the
install's effective channel (up_to_date, available, no_release,
rate_limited, network_error, metadata_error, skipped, error), tagging
lookup failures without changing their error text, and ignores previews of
another channel from Settings. Telemetry schema v18 exports update_channel,
update_check_outcome and update_available. No version, URL or error text
leaves the install. The Settings preview type, privacy disclosure, adoption
report and subsystem contracts are updated to match; the Pulse Pro receiver
change lands separately and the parity check passes against it.
ARMv6 and ARMv7 server binaries both report GOARCH=arm. Read the release binary GOARM build setting and fail closed when it does not name a published server archive, rather than offering an ARMv7 update to ARMv6 installations. Cover the architecture mapping and document the installability boundary.
Change-source: pulse-maintainer