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.
The isolated coverage-v8 5 proposal cannot install beside Vitest 4 because its peer range requires Vitest 5. Ignore only version majors for both packages until a reviewed frontend migration can update and prove the pair together; retain grouped security updates and minor/patch updates.
Change-source: pulse-maintainer
Keep ESLint 10 and lucide-solid 1.x out of automatic version updates while their lockfile and icon-import contracts fail. Preserve minor and patch updates and guard the rule in Dependabot policy tests.
Change-source: pulse-maintainer
The release-promotion guard still expected the old installer-link wording,
so it rejected the corrected helper-ownership and version-pinning guidance.
Separate the installer safety assertions from support-pack coverage and
check the signed fallback, rollback applicability and version verification.
Rejected active-alert writes still reached history, firing events and
notification dispatch. Make admission explicit across detector and restore
paths so repeated suppressed observations cannot create those side effects.
Reconcile restored alerts when persisted resource policy attaches at startup,
reconcile again after native aliases become canonical, and refresh shared
state before those alerts reach clients.
Preserve occurrence identity when retained alerts re-fire, including durable
history reconstruction and delayed lifecycle replay.
Keep retained table and card components mounted when scrolling shifts the
visible window, so policy editors do not lose unsaved state. Show actual
future maintenance times and the paused-attention effect.
Keep synthetic host machine identities stable across restarts so saved
operator policy remains attached during verification.
Qualify server update and rollback instructions by helper ownership, and
stop signed installer recipes before execution if a download or signature
check fails.
Refs #2237
setup.sh resolves the image pins in .env to digests once, so upgrade.sh
only ever re-pulled the release a provider first installed. Moving to a
new release meant finding the new digests by hand, so none of a release's
fixes, and no new feature such as the portal Plan tab, reached an
existing install.
Run from a newly extracted release bundle, upgrade.sh now works on the
existing install: it resolves the bundle's control-plane and runtime tags
to digests, runs the status gate, preflight and verified backup with the
new release's control plane through a shell override while nothing on
disk changes, then keeps a copy of .env, installs the bundle files and
writes the new pins before starting the new images. --keep-image-pins
keeps hand-set pins.
It also pulls the tenant runtime image before the first status check,
which otherwise failed every upgrade to a new CP_PULSE_IMAGE with "not
present locally", including the documented pin-editing route.
Exercise two provider installations with the same tenant ID, unowned-network collision and cleanup isolation. Gate the release-line push before packet freeze and repeat against digest-verified candidate images during container qualification. Update the deployment-installability contract and pin both workflow gates in the release-asset verification suite.
Change-source: pulse-maintainer
Keep first-run evaluation and summary guidance conditional on actual Plan availability and confirmed active limits. Remove the ordinary manual-key purchase prompt while retaining the separate custom-license binding path, and update the installability contract and focused assertions in the same commit.
Change-source: pulse-maintainer
setup.sh still told an evaluating provider to "request an upgrade" at
/msp.html#request, a form that waited on a human reply with a checkout
link. The portal now sells plans itself (Plan tab, Stripe checkout,
applied in seconds), so both the evaluation log line and the closing
summary send the provider there. The summary also stops printing the
lease signing public key as something the licence "must bind": the
portal purchase binds it without a copy step, and the key is still
available through --print-lease-signing-public-key for a custom licence.
Start the provider services after licensed compose validation so the printed bootstrap and portal link have a live control plane. Correct the first-run prompt to name only operator-provided values and retain an install contract regression test.
Change-source: pulse-maintainer
Every stable cut re-pins CANONICAL_DEFAULT_PULSE_VERSION in
scripts/install-docker.sh from the RC to the stable version, and the
stable install-metadata test requires it. The drift allowlist omitted
that file, so no release candidate could be promoted without
hotfix_exception. The rule arrived on 2026-09-01, after v6.4.1, so no
stable promotion has run under it yet. v6.4.5 would be the first to fail.
The installer is shipped content, so the resolver accepts it only when
its diff against the candidate changes nothing but that pin line. Any
other installer change still counts as drift.
Go _test.go files are never compiled into a shipped artifact. A stable
cut can need test-only corrections, as v6.4.5 needs for the RC-derived
install-metadata contract, so they no longer count as unsoaked content.
Tests cover the allowed shapes, the refused near misses, and the pin
check against a real git diff.
Keep the canonical release and provider-MSP frontend builders on the proposed immutable amd64 Node 24 digest. Bind the same-commit change to the deployment contract, release-build metadata proof and provider-MSP rollout-control proof; hosted build and installed rollout remain separate evidence.
Change-source: pulse-maintainer
The Backups drawer's Identity and History target is the merged PBS host resource. Correlation was recomputed from each snapshot with no memory, so a live refresh that briefly omitted the correlated host row made the drawer fall back to the PBS service target (agent/<service key>), which has no host history. The target flicked between the host series and the service key until the host row returned.
Retain the last resolved correlation per PBS server and reuse it only across such an omission, and only while the remembered host is still fresh relative to the server, so a genuinely removed or replaced host is not advertised indefinitely. A host row that is present but ambiguous still declines, as before.
Adds unit coverage for retention, staleness and pruning, a drawer regression test, and extends the real-browser guard and fixture to omit the host row and assert the identity rows and History chart survive.
Change-source: pulse-maintainer
action_consumer_manifests.json pins each release-consumed action to an exact SHA plus the upstream action.yml sha256, and release_promotion_policy_test.py requires every workflow step to match. Dependabot's github-actions group bumps those SHAs, so every group proposal fails the manifest contract and cannot be repaired offline. Ignore the eight governed actions for version updates and guard the policy against the manifest so pin refreshes stay explicit reviewed work. This resolves the recurring failing actions-minor-patch proposal (#2139).
Change-source: pulse-maintainer
Advance the managed go-minor-patch group with its required transitives:
golang.org/x/crypto 0.56.0->0.57.0, golang.org/x/term 0.45.0->0.46.0 and
modernc.org/sqlite 1.53.0->1.59.0 (libc 1.75.7, memory 1.12.1, x/text 0.42.0).
All other direct versions are unchanged.
Raise the dev-runtime dependency-manifest floors to the qualified releases and
add the storage-driver integrity floor so a silent downgrade fails. Record the
change in the deployment-installability contract.
The batch is routine managed dependency maintenance, independent of the excluded
6 September SQLite SIGSEGV investigation. The NormalizeSegment benchmark delta is
a code-layout measurement artifact (pure function; caller benchmarks do not
corroborate) and the failed advisory result is preserved.
Change-source: pulse-maintainer
Dependabot #2100 and #2101 propose TypeScript 5.9.3 -> 7.0.2, but the checked-in @typescript-eslint/eslint-plugin@8.70.0, @typescript-eslint/parser@8.70.0 and typescript-eslint@8.70.0 each declare a peer dependency of "typescript": ">=4.8.4 <6.1.0". The proposals therefore fail ERESOLVE and all frontend E2E shards, with no security advisory behind them.
Add a semver-major ignore for typescript in the npm ecosystem so majors stay explicit work alongside a lint-toolchain upgrade, and update the config guard test to pin both the browser-runtime and TypeScript ignores.
Change-source: pulse-maintainer
The install-metadata contract encoded only the emergency no-RC stable-patch shape. A stable patch with a same-version RC promotes the exercised candidate (promotion_mode stable-rc-promotion), so the contract must assert that shape and derive the rollback target from the last published stable.
previousStablePatchVersion hardcoded only v6.4.2 as unpublished, so v6.4.5 rolled back to the never-published v6.4.4. Add v6.4.3 and v6.4.4, which only ever shipped as prereleases, so v6.4.5 resolves to the published v6.4.1 that the promotion resolver also derives.
Add stablePatchPromotedPrerelease to detect the same-version candidate from the retained release notes, and branch the stable-patch install-metadata tests between the emergency and RC-derived shapes. Unit tests pin the rollback derivation and the candidate detection.
Change-source: pulse-maintainer
The FreeBSD rc.d branch printed a log hint pointing at the system log,
but pfSense has no /var/log/messages (its system log is
/var/log/system.log). More importantly, daemon(8) does not capture the
child's stdout and rc.d has no journal, so the agent's zerolog output was
never written to any file: correcting the path alone would still point
users at a log with no agent entries.
Give the agent its own rotating log via --log-file on FreeBSD (both the
TrueNAS CORE and pfSense/OPNsense/vanilla FreeBSD branches) and point the
completion hint at it, matching the Unraid/QNAP/TrueNAS-Linux convention.
The shell installer is a canonical path shared by agent-lifecycle and
deployment-installability, so record the FreeBSD log-capture obligation in
both subsystem contracts.
Refs #2123.
Change-source: pulse-maintainer
A live resource snapshot can briefly omit a field that gates a drawer tab, for example a merged metrics target during a refresh. The tab guard reset the active tab to Overview whenever the selected tab was missing, so the reported Proxmox -> Backups History tab silently jumped back to Summary on data refresh. Reset only when the drawer starts showing a different resource; each tab body already renders an availability notice while its tab is transiently unavailable. Adds a regression test covering a snapshot that drops and restores the metrics target, a source guard in ResourceDetailDrawer.history.test.tsx, the unified-resources contract update, and a fresh frontend browser-verification receipt from scripts/check-drawer-tab-retention.cjs (the same check times out on the pre-fix source).
Change-source: pulse-maintainer
The Backups drawer renders Discovery and Metrics Target from the merged host resource, so a snapshot-driven correlation change would silently flip those labels. Add discoveryTarget to the retained real-browser fixture and assert both identity rows stay present and byte-identical across reordered, timer-driven snapshots and datastore switching. The guard passes on the current source; it does not reproduce the reporter's live target-spelling flicker.
Change-source: pulse-maintainer
Extend the PBS History regression to PBS-only and bare-metal PVE/PBS host shapes, stable and reordered snapshots, and desktop/mobile widths. Retain guest coverage and assert drawer identity, tab selection and history targets. This does not claim the separate reported tab reset is reproduced or resolved.
Change-source: pulse-maintainer
Detach each rendered datastore from the nested PBS snapshot so independent row reconciliation cannot overwrite another datastore's identity. Cover switching and refreshed History in the component regression and real-browser fixture for #1723.
Contract-Neutral: Restore existing PBS datastore row identity during snapshot reconciliation; no API or canonical ownership change.
Change-source: pulse-maintainer
A standalone source=pbs host row and the PVE guest carrying the same agent are one machine. Collapse correlation candidates that share an agent identity and prefer the guest metrics target, whose persisted host series the Backups drawer renders; the PBS service target names the service key and has no host history. Distinct agent identities, or rows without a provable identity, still decline to choose so the drawer cannot substitute an unrelated host. Re-compose the reviewed runtime change with its three subsystem contracts, offline browser fixture, check script and a content-addressed browser receipt in one governed commit.
Change-source: pulse-maintainer
Register 8b56fc72e4 with its contract-completion commit so canonical governance evaluates the reviewed Proxmox LXC linked-agent memory runtime change and its monitoring and unified-resources contract sections as one historical unit.
Change-source: pulse-maintainer
The secure-runtime RC qualification workflow (commit 79d87a4a2c) resolves the branch the control plane maps the version to and passes it as --main-ref, but secure_runtime_attestation_v6.verify_canonical_main_identity still required origin/main and required the candidate to be an ancestor of origin/main. Every release-train candidate therefore failed the pre-authentication step before any check ran; v6.4.5-rc.1 failed at 'Pre-authenticate exact qualification packet' with 'committed-main classification requires canonical origin/main' (run 35680955017), and all three historical runs failed.
Accept exactly origin/main or the release train's origin/release/vX.Y, verify the ref against the canonical origin's live branch tip, and check candidate ancestry against that same ref. The release-candidate classification is unchanged. Update the deployment-installability contract and the v6 unit tests, including a mapped-release-branch acceptance case.
Change-source: pulse-maintainer
The Alerts overview alert-card footer is an items-center flex row whose first child, the Started timestamp, carried its own mt-1. Under items-center that margin shifted the Started run 2px below the adjacent delivery-status run, which is the small text misalignment the reporter underlined in #2119. Remove the child margin; the footer row already carries the top margin, so the two runs share a baseline.
Add a presentation regression test and an offline browser proof that measures the text rects of both runs at desktop and narrow widths.
Contract-Neutral: Behavioral footer-alignment fix; no public-contract or subsystem-shape delta.
Change-source: pulse-maintainer
Register the two #2140 runtime commits with their contract and proof completion commit so the canonical completion guard evaluates each runtime change together with the follow-up that records its contracts and verification artifacts, as one reviewed unit. Registry-only change; no runtime behaviour.
Change-source: pulse-maintainer
Lands contributor PR #2067 (head 5eeea72a3a, author rcourtman) as a single maintainer commit on main. The PR documents the authenticated /api/resources/{id}/operator-state maintenance window contract and repairs GitHub-compatible documentation heading fragments.
Composed from the reviewed web-product candidate tree 68465bc48d (candidate 20260921T054028Z-web-product), which resolved the conflicts against main and replaced the unavailable github-slugger dependency with a dependency-free GitHub-compatible heading slugger. The tree is unchanged from that reviewed candidate; only the commit shape differs so the fdb2be15be..HEAD provenance range contains no external PR commit.
Validation retained from that candidate: vite build passed, check-bundle-size.mjs passed (vendor within budget), 61 focused vitest tests passed, and the offline Playwright docs-fragment-navigation run passed with a content-addressed browser-verification.json receipt based at fdb2be15be.
Change-source: pulse-maintainer
Pair the windowed item-height estimate repair (6f0dc177c8) with its contract completion commit (8738eb1bff) so the per-commit canonical guard evaluates them as one reviewed unit.
Change-source: pulse-maintainer
The virtual window measured only the top spacer's first sibling. On grouped
surfaces that sibling is a short group header, so the estimate collapsed to
the header height and the mounted window advanced roughly one row per header
height of scroll. The Alert Thresholds card list then dropped a host's rows
while scrolling and its Ctrl-F match count oscillated.
Measure the tallest of the first few rendered siblings so a leading header
cannot collapse the estimate, while uniform tables still measure their real
row height. Add a regression test and offline browser proof.
Change-source: pulse-maintainer
Register the server startup-stall watchdog runtime commit and its shared
follow-up contract/proof commit in the canonical completion history so the
per-commit guard evaluates the pair as one reviewed unit.
Change-source: pulse-maintainer
Integrate the reviewed failed-staging config-backup discard repair (07d54cd345)
with its deployment-installability contract, installtest proof and registered
completion pair (ccfd22da7f, b36e9609dd). The candidate auto-update RETURN-trap
repair (9b004cc787) duplicates the already-integrated 564c235e32, so the merge
keeps the canonical trap implementation and both regression suites and retains
both registry entries. Change-source: pulse-maintainer
Change-source: pulse-maintainer
Register the two update-path runtime commits and their shared follow-up
contract/proof commit in the canonical completion history so the per-commit
guard evaluates each pair as one reviewed unit.
Change-source: pulse-maintainer
Record the deployment-installability contract section for the auto-update
RETURN-trap and failed-staging config-backup repairs, and add the Go proof
that exercises the extracted perform_update and asserts the trap does not leak
into a later function return. This completes the two runtime commits for
canonical governance as one reviewed unit each.
Change-source: pulse-maintainer
Register 564c235e32 (runtime) with bb25e3ec03 (contract + Go proof) as a
reviewed completion unit so the per-commit canonical guard evaluates them
together rather than rejecting the runtime commit for a missing same-commit
contract and verification artifact.
Change-source: pulse-maintainer
Follow-up to 564c235e32 (fix(update): disarm perform_update RETURN trap after
it runs). That runtime change touches the deployment-installability subsystem,
so this commit adds the matching substantive contract section in
docs/release-control/v6/internal/subsystems/deployment-installability.md and
the registry-accepted deployment-script-runtime proof in
scripts/installtests/pulse_auto_update_test.go
(TestPerformUpdateDoesNotLeakReturnTrap). The pair is registered in
scripts/release_control/canonical_completion_history.json by the next commit.
Change-source: pulse-maintainer
backup_existing snapshots the configuration before the update stages, but a
staging disk-headroom failure then exited and left that snapshot behind. On a
small root filesystem each automatic retry added another full backup and made
the low-space condition progressively worse until updates could no longer run
(#2127). Record the snapshot and remove it when download_pulse aborts at the
headroom check, before anything was replaced. Add regression coverage.
Change-source: pulse-maintainer
The RETURN trap installed inside perform_update is shell-global and was left
installed after the function returned. It fired again when a later function
returned, expanding the now out-of-scope local installer_tmp/signature_tmp
under set -u, so pulse-update.service reported a successful install as failed
with 'installer_tmp: unbound variable' (#2128). Clear the trap as it runs and
cover it with a regression test.
Change-source: pulse-maintainer
A RETURN trap is not scoped to the function that installs it. perform_update
left its trap referencing function-local installer_tmp/signature_tmp (and
service_name/service_was_active) installed, so it re-ran when a later function
returned. With those locals gone and 'set -u' active, the updater aborted with
'installer_tmp: unbound variable' immediately after logging 'Auto-update check
completed' — pulse-update.service entered failed state even though the update
had succeeded (reported #2128, affects v6.3.2/v6.4.1).
Disarm the trap with 'trap - RETURN' on its first invocation, and use
${installer_tmp:-}/${signature_tmp:-} so a stray invocation cannot abort the
script. Add a regression test asserting no RETURN trap remains after both the
successful and the prerelease-refusal paths.
Change-source: pulse-maintainer
Record the unified physical-disk SMART runtime commit abaca8f9c0 and its
contract/proof follow-up 33260be25b as one reviewed completion unit so the
per-commit canonical guard evaluates the pair together.
Change-source: pulse-maintainer
Bind the create-release pair preflight commit to the follow-up contract and proof commit as one reviewed completion unit, matching the existing canonical completion history entries.
Change-source: pulse-maintainer
The create-release prepare job now verifies that pulse-enterprise declares docs/release-source-pairs/<expected_source_sha>.json and that it names the frozen public commit before any draft release object exists. Record that obligation in the deployment-installability contract and add the release-promotion policy proof that guards the step and its ordering ahead of create_release.
Change-source: pulse-maintainer
Dependabot #2094, #2095 and #2096 bump actions/setup-go 6.4.0 -> 7.0.0, signpath/github-action-submit-signing-request 2 -> 3.0 and actions/github-script 8.0.0 -> 9.0.0. Each proposal is blocked only by the reviewed pin constants, the workflow-trust allowlist, the release-consumer action manifest and the installer governance assertions that hard-code the previous revisions. Carry all three bumps with those artifacts in one commit so the proposals can be closed as superseded.
All three actions keep the node24 runtime and their existing inputs and outputs; no consumer interface, installer behaviour or public contract changes. The deployment-installability and agent-lifecycle workflow references are pin-only.
Contract-Neutral: Reviewed action pin refresh with identical node24 consumer interfaces and unchanged inputs/outputs; no public-contract or installer-behaviour delta.
Change-source: pulse-maintainer
Register the reviewed completion pair for the TrueNAS legacy-REST memory telemetry runtime commit and its contract/proof follow-up so canonical governance evaluates them as one unit without rewriting history.
Change-source: pulse-maintainer
The npm-minor-patch group (Dependabot #2115) has been held since 17 Sep
because it bundles @playwright/test, playwright and playwright-core
1.56.1 -> 1.63.0 with 12 safe frontend updates. The offline
browser-verification runtime is pinned to Playwright 1.56.1, so a lockfile
bump breaks browser-proof parity; holding the whole group blocked the safe
updates instead.
Ignore Playwright version updates on the governed 1.56.1 line, matching the
docker governed-tag policy, so the remaining grouped updates can be reviewed
on their own. Security updates stay covered by the weekly npm-audit scan and
the frontend dependencySecurity proof. Extend the dependabot config guard to
lock the policy in.
Change-source: pulse-maintainer
Register the reviewed completion pair for the FreeBSD checksum-tool fallback runtime commit and its contract/proof follow-up so canonical governance evaluates them as one unit without rewriting history.
Change-source: pulse-maintainer