Commit Graph

2647 Commits

Author SHA1 Message Date
rcourtman 03132e8782 Reduce workload chart overhead and repair browser test setup (#3233)
Cold seven-day mock workload charts synthesized 914 values per series
before discarding most of them. Selecting the existing timestamp grid
before synthesis preserves the retained readings, newest point and
complete history window while bounding expensive work. The controlled
native request fell from 8.9 seconds to 1.3 seconds.

The strict chart query gate also exceeded its 90 ms p95 limit. Profiling
showed repeated SQLite row decoding, so raw fleet value reads now carry
the series and timestamp in one integer per observation. This
statement-local transport preserves exact values, negative-epoch
timestamps, tier reconciliation, resource scope and ordering, with
separate columns when a window could overflow. Full metrics-store tests
and targeted monitoring/API regressions pass, including boundary and
prepared-query cache controls. The 90 ms limit remains unchanged.

Organization browser fixtures arrange activated API fixtures before
their first workspace load. Explicit activation and deletion bounds
cover the existing server deadlines. Cleanup owns partial preparation,
attempts every tracked organization and retains failures. Native backend
teardown retains its final log. CI executes all 63 authentication,
organization and backend lifecycle controls before browser fanout.

Browser OS acquisition uses the hosted runner's existing signed Ubuntu
source definition. An unrelated Microsoft feed returning 403 can no
longer stop browser setup. Missing, unreadable or empty Ubuntu
definitions and incomplete Ubuntu index updates still fail. Existing
mirror, TLS, signature and cached archive hash checks remain in force.
Real apt acquisition controls, 17 package cache tests, 11 ownership
tests and normal commit/push checks pass.

The mock target lookup benchmark keeps fixture lifecycle logs out of
Go's result stream. A combined stdout/stderr control reproduces the lost
original observations and parses all ten corrected observations with
identical 4,731 lookups per operation. The benchmark work and comparison
thresholds remain unchanged.

Current-build browser verification covers
`/proxmox/workloads?type=vm&platform=proxmox-pve` at 1440×1000 and
390×844: seven-day trends, row drawer expansion, history range
selection, oldest/latest keyboard inspection and drawer dismissal.
Twelve organization-route cases cover organization settings, access,
sharing and billing across Chromium, mobile Chrome and mobile Safari
with retries disabled.

The [full stable/probation browser
run](https://github.com/rcourtman/Pulse/actions/runs/40160832317)
passed: 530 passed, 392 skipped, zero failures and no retry/flaky
markers in all eight shard logs. Agent registration and organization
provisioning also passed. This evidence covers product code at 64c0a3f9.
The later correction changes only a Go benchmark fixture and its
performance contract.

The [final-head stable E2E
run](https://github.com/rcourtman/Pulse/actions/runs/40163545118) also
passed all eight shards, agent registration and organization
provisioning: 186 passed, 183 skipped, zero failures.

All nine required source checks passed. The [final-head build and test
run](https://github.com/rcourtman/Pulse/actions/runs/40163545117)
passed, including benchmark comparison and strict chart qualification.
The chart result on valid hosted capacity was p50 38.31 ms, p95 51.01 ms
and p99 52.28 ms against the unchanged 90 ms p95 limit. The retained
artifact binds the measured binary to the tested synthetic merge commit.
The preceding runtime qualification also passed at p95 86.55 ms on its
runner. The benchmark comparison found no regression above the existing
10% and p<0.05 threshold. The corrected lookup fixture supplied all ten
observations without parser warnings.

After main advanced with scoped authentication and tenant runtime
changes, a native compatibility proof composed this exact head with
c809d3c93b. API, configuration API and
monitoring regressions passed. All twelve organization browser cases
passed again with retries disabled. A fresh embedded runtime passed the
desktop and phone seven-day chart matrix with both endpoints accessible.
The reviewed combined tree is 2e9a154b1c.
2026-10-25 05:27:11 +00:00
rcourtman 64c0a3f9df Scope browser OS acquisition to the runner's signed Ubuntu sources
An unrelated Microsoft repository returned 403 during fresh-index admission and stopped a browser shard before any test could run. Load the hosted runner's existing Ubuntu Deb822 definition for browser packages, preserving its mirrors and signature policy. Fail when that definition is missing, unreadable or empty and keep strict index and archive hash checks.

Exercise the real apt parser, exclusion of unrelated feeds, missing definitions and incomplete index failures in private acquisition directories. Register the package helper and policy with their exact verification routes, and update the fixture helper's governance assertion to its scoped proof contract.
2026-10-25 04:00:03 +00:00
pulse-triage[bot] 7adfe647fe Keep local safety checks effective on large staged changes
Admit the complete index and patch reads, and drain pattern matches before interpreting their result under pipefail. Preserve sensitive-file and fallback-secret blocks and required docs, governance and lint admission; distinguish an empty filtered patch from a failed read. Exercise the actual hook with bounded synthetic large inputs and retained failure exits.

Contract-Neutral: Local hook input handling only; existing secret patterns, required checks and production contracts are unchanged.
Change-source: pulse-maintainer
2026-10-25 03:33:27 +00:00
pulse-triage[bot] e1e2860d35 Fix accessible controls, resource provenance and deep drawer scrolling (#3222)
Scrolling through a long platform drawer could unmount its owning row
and close the detail being read. REST resource projection also dropped
source provenance, hiding vCenter context and host placement from
owning-snapshot consumers. Diagnostic commands lacked keyboard
scrolling, and dark-theme text and several Patrol control names failed
accessibility checks.

Measure summary rows and inline details together in the shared bounded
window, preserve canonical resource sources, make diagnostic command
blocks focusable, and repair shared contrast and visible control naming.
Browser fixtures await mounted authentication and keep synthetic
provider inventory authoritative. Journey assertions follow current
read-only capabilities, technical disclosures and composed resource
queries. Long settings audits traverse the actual scroll extent; curated
estate checks use native inventory disclosures and search; disk proofs
follow canonical serial-bound shared history; the published
completed-restore-point calendar checks remain intact, including day
selection and filter reset. Update API proofs no longer mount an
unrelated dashboard before each request.

Fresh password login now waits for mounted bootstrap too. The
delayed-bootstrap regression owns and revokes its own token, so it runs
with cookie-only and primary-token fixtures without replacing the
fixture credential. Update API cases share an admitted cookie fixture.
Growth assertions use the current fixed-window header, LXC refresh
assertions use the fixture's canonical identity, and the gated-panel
observer follows actual gate readiness while still detecting visible
unlocked controls. The Docker browser stack explicitly opts into a
bounded development update budget for its shared bridge IP. Production
and login limits remain unchanged.

The remaining recovered failures exposed three test synchronization
defects. Alerts now leaves the whole editor before judging a staged
change and exercises its sibling-focus contract. Protected panel
assertions wait for mounted bootstrap before their existing readiness
timeout. The delayed-token regression uses its own page, avoiding
interception of reads from a departing setup document. CI retains
failed-attempt HTML diagnostics after a successful retry and small JUnit
results for each completed tier, including stable receipts before
probation starts.

Validation includes negative controls for the original drawer,
provenance and password-bootstrap defects, 335 focused frontend tests,
23 authentication-fixture tests, type-checking and a production build.
The cookie-only follow-up matrix passed 39 cases across Chromium, mobile
Chrome and mobile Safari with 18 existing skips. Twelve additional
onboarding cases passed with no retries, and the token-bootstrap matrix
passed 12 cases with cookies alone and 12 with a primary token. Native
Chromium and WebKit checks exercise the gated-panel detector's positive
and negative controls. The earlier remaining-failures matrix passed 31
cases with 10 existing skips, and both disk-history cases passed on
desktop.

Current-build browser verification covers onboarding, accessibility,
VMware context and exclusion boundaries, demo commercial isolation,
persisted Alerts settings, Patrol, availability and background refresh.
Pixel and interaction review covers infrastructure, Agent Doctor,
Patrol, Docker, Kubernetes and vSphere at desktop, tablet and phone
widths in both themes where applicable. Existing timeouts, skips,
mounted-row limits and the 90 ms chart budget remain in place.

The final recovered-failure matrix passed 27 cases with 14 existing
mobile skips using cookies alone, followed by 12 passes with a primary
token, all without retries. The forced desktop table control reproduces
the old focus failure and passes after leaving the editor. The preceding
qualified tree completed all required source checks and the full
stable/probation matrix. Its executed strict chart proof measured p95
61.1 ms against 90 ms with valid capacity. The updated head is being
qualified again before landing.

Governed work: L12 journey verification and the shared L10 windowing
proof. This source change does not publish a release.
2026-10-25 02:30:21 +00:00
pulse-triage[bot] 7b64d9b66d Keep real NAS process-inventory controls serial
The first exact-source parallel attempt failed the generated Unraid and QNAP watchdog control. Its real machine-wide process observation is not isolated by private fixture files. Preserve the entire NAS class's serial execution and make concurrency explicit only for the seven modelled-inventory classes. The regression now proves that the serial helper still preserves ordering, as well as bounded parallelism and complete failure/skip/cleanup evidence.

Contract-Neutral: Test-only fixture scheduling; real NAS observations, production manager deadlines, process ownership checks and required test coverage are unchanged.
Change-source: pulse-maintainer
2026-10-25 01:15:42 +00:00
rcourtman 2a149603f0 Run native settings scroll regressions in browser CI
Exercise Chromium and WebKit geometry once after browser installation,
before the first shard admits its runtime fixture. Content growth must
complete the new scroll extent and unchanged-extent resets must still fail.
2026-10-25 01:54:59 +01:00
pulse-triage[bot] d291080a8f Run isolated installer safety controls within Go's parallel budget
Current successful public CI puts the installer package on the backend critical path for 683-764 seconds. Each registered Python method already owns a separate process and private fixtures; run those methods through the existing Go parallel scheduler, starting their unchanged deadlines only after admission. Keep exhaustive discovery and exact non-skipped method verdicts, with connected parallel, serial, failure, skip and cleanup controls.

Contract-Neutral: Test-only scheduling of already isolated fixture processes; no installer, runtime, service deadline, source selection, required check or native acceptance contract changes.
Change-source: pulse-maintainer
2026-10-25 01:51:34 +01:00
rcourtman 72f6d2cf7d fix(e2e): synchronize editor commits and retain retry diagnostics
Judge consuming panels after their protected document has mounted, and
give the delayed-token regression its own bootstrap page. Leave the whole
Alerts editor before checking for a staged change, including its desktop
focus and card Save contracts. Keep the existing panel timeouts.

Preserve failed-attempt HTML diagnostics when a first retry succeeds and
retain small JUnit results for every completed tier. Upload stable evidence
before probation starts. Integrate the published node disk observation
repair before qualification.
2026-10-25 00:33:48 +01:00
rcourtman c0c54de765 fix(e2e): await authenticated bootstrap in cookie-only fixtures
Fresh password login must await the mounted workspace before a caller
opens an onboarding route. Own and revoke the bootstrap regression token
without replacing the primary credential, and bootstrap update API tests
once per worker when CI provides cookies alone.

Opt the synthetic shared-IP stack into a finite development update budget
without changing production, authentication or configuration limits.

Observe gated panels through actual gate readiness. Keep the fixed 24h
growth assertion on its native header and select the retained LXC drawer
with the fixture's canonical resource identity. Integrate the published
filesystem-observation and issue-topic repairs before qualification.
2026-10-24 23:50:14 +01:00
rcourtman 708e8f94fb merge: reconcile current monitoring and E2E contracts
Preserve published absent-disk, completed-backup and accessible-name fixes
alongside the verified drawer and resource-provenance changes.

Follow native inventory disclosures, full settings scroll geometry and
shared disk-history responses so browser proofs exercise the current UI
without weakening row, layout, signature or chart-latency budgets.
2026-10-24 22:39:27 +01:00
rcourtman 58f9398a41 fix(e2e): preserve accessible controls and deep drawer navigation
Preserve source provenance in REST-loaded resources so owning-snapshot
consumers retain provider context and host placement. Keep visible control wording in accessible names and retain readable command
and navigation text in both themes. Token fixtures now await mounted browser
bootstrap before handing control to the next journey.

Measure bounded platform table items together with their inline details so
scrolling down a tall drawer cannot unmount the resource being inspected.
Retain regression coverage for bootstrap timing, drawer state and scroll
extent, responsive controls, Patrol and availability, and align navigation
assertions with current read-only capabilities and composed resource queries.
Provider fixtures retain one authoritative inventory across transport updates.
2026-10-24 21:41:34 +01:00
courtmanr@gmail.com c4486a177a Keep a real change out of the Highlights example
The Highlights guidance used "Resource Overview shows alerts, recent
trends and longer history together" as its example. That is a real
v6.6.0 change, and a test draft of the v6.6.0 notes copied it almost
word for word, so a later release could repeat it as if it were new.

The generator and the release-notes template now describe the shape
instead, the page or feature and then what it now does, and say to
describe only changes in this release. The slogan counterexamples stay,
and the release-assets test pins the new sentence.
2026-10-24 20:43:52 +01:00
rcourtman 97f55638c9 Prove demo auto sign-in in the public browser smoke (#3204)
Since v6.5.0 demo mode signs a fresh visitor in with the published
demo credentials, so the login form never stays on screen for a first
visit. The browser smoke still waited two minutes for that form and
failed, which blocked every stable demo convergence once the Tailscale
step worked again. It went unnoticed because the demo update had not
got past Tailscale since v6.5.0 shipped.

The smoke now proves the visitor's real path, a fresh tab reaching the
connected workspace, when the server reports demo mode. A second
context sets the frontend's own pulse-demo-auto-login marker to keep
proving the login form and a manual demo sign-in. Against the live
demo the old script times out and the new one passes both phases. The
policy test pins the marker to localStorage.ts so a rename fails in
source checks rather than on the live demo.
2026-10-24 15:06:41 +01:00
rcourtman 572930fded Make release Highlights name concrete changes (#3203)
Make release Highlights name concrete changes

The generator only asked for "one to three plain-text outcomes", so it
produced slogans such as "See problems, recent trends and longer
history together" that tell a user nothing about what changed. These
lines are what the update banner shows before someone installs.

The generator prompt and the release-notes template now ask for the
release's biggest specific changes and where users find them, with an
example and named anti-examples, and the release-assets test pins that
wording. Their description of the post-update modal also follows the
new plain changelog, which no longer collapses upgrade notes or puts
Highlights above the changes.
2026-10-24 14:45:36 +01:00
rcourtman df79b7716a Prove demo auto sign-in in the public browser smoke
Since v6.5.0 demo mode signs a fresh visitor in with the published
demo credentials, so the login form never stays on screen for a first
visit. The browser smoke still waited two minutes for that form and
failed, which blocked every stable demo convergence once the Tailscale
step worked again. It went unnoticed because the demo update had not
got past Tailscale since v6.5.0 shipped.

The smoke now proves the visitor's real path, a fresh tab reaching the
connected workspace, when the server reports demo mode. A second
context sets the frontend's own pulse-demo-auto-login marker to keep
proving the login form and a manual demo sign-in. Against the live
demo the old script times out and the new one passes both phases. The
policy test pins the marker to localStorage.ts so a rename fails in
source checks rather than on the live demo.
2026-10-24 14:31:21 +01:00
courtmanr@gmail.com 842dbda6b8 Make release Highlights name concrete changes
The generator only asked for "one to three plain-text outcomes", so it
produced slogans such as "See problems, recent trends and longer
history together" that tell a user nothing about what changed. These
lines are what the update banner shows before someone installs.

The generator prompt and the release-notes template now ask for the
release's biggest specific changes and where users find them, with an
example and named anti-examples, and the release-assets test pins that
wording. Their description of the post-update modal also follows the
new plain changelog, which no longer collapses upgrade notes or puts
Highlights above the changes.
2026-10-24 14:06:27 +01:00
rcourtman 1ffa17a10c Merge remote-tracking branch 'origin/main' into fix/demo-tailnet-ci-deploy-client 2026-10-24 13:28:42 +01:00
pulse-triage[bot] 06475a9d37 Keep bounded hosted provisioning overhead in chart SLO verdicts (#3199)
Retained hosted samples include both an over-budget failure and an
under-budget pass with one provisioning agent occupying about one
logical CPU. Attribute only that bounded Actions overhead; retain raw
CPU and absolute 90 ms latency, and keep other or unattributed CPU,
guest, steal and swap invalidating. Exercise the real CLI and workflow
shells with adverse controls; no timed workload or release acceptance is
claimed.

---
Fleet candidate `20261024T104012Z-delivery-trust` from the
`delivery-trust` lane. Reviewed tip
`fbe410e244f3d44b44de258c6f3db68dabd257da` on `main`.

[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
2026-10-24 12:27:42 +00:00
rcourtman bc39aa5908 Move demo deploys to the tag:ci-deploy Tailscale client
The demo update and recovery workflows still joined the tailnet with
the July 2026 tag:infra OAuth client. That client was revoked on 30
September, when the private repositories moved to narrow clients, and
the public repository was missed. Since then every demo convergence
step has failed with an OAuth 401, so stable releases cannot converge
and the hourly reconcile keeps retrying v6.5.0.

Both workflows now use the TS_CI_DEPLOY_OAUTH_* binding that the
browser update qualification already expects, restricted to
tag:ci-deploy. The tailnet policy already grants that tag SSH to
pulse-relay, the demo host, so no policy change is needed. One narrow
client now serves all three workflows, and the broad tag:infra
identity is gone from this repository.
2026-10-24 13:25:23 +01:00
rcourtman 82df77f2f5 Treat a deleted convergence owner as terminal (#3197)
Treat a deleted convergence owner as terminal

The hourly "Reconcile release convergence debt" job has failed every run
since 13 Oct. The v6.5.0 activation marker names convergence run
37395942598 as its owner, and that run was deleted from Actions with the
rest of the 30 Sep - 8 Oct release history. The immutable marker
outlives
Actions history, so the reconciler and release-convergence.yml both
waited
forever on an owner that can no longer be read, and the permanently red
job hid real failures such as the rc.6 paid-broker miss.

GitHub only deletes a run that has completed or is older than two weeks,
which is beyond every convergence job timeout, so a definite 404 is a
terminal owner. Both the reconciler and the successor's adoption wait
now
proceed from the validated marker in that case. Any other read failure
still waits or fails.

Also remove the workflow_run retry job. Convergence runs are dispatched
with GITHUB_TOKEN, and GitHub does not deliver workflow_run for them:
the
job fired seven times ever, each for a run an operator started by hand,
and never after 29 Aug while dozens of bot-dispatched failures were
recovered by the hourly schedule. The schedule is documented as the
retry
mechanism.

v6.5.0 is served on every surface (Docker aliases at the marker digest,
Helm index entry, paid broker, demo /api/version), but no convergence
run
has proved it. The next scheduled pass dispatches a fresh v6.5.0
convergence; its demo surface will fail until the Tailscale OAuth client
behind TS_OAUTH_CLIENT_ID/TS_OAUTH_SECRET is rotated, as it returns 401.
2026-10-24 12:45:42 +01:00
rcourtman 5e30ff791a Re-dispatch Pro promotion refused by a moved pulse-pro main (#3193)
pulse-pro gives a promotion run credentials only while that run is
still its current main. Any pulse-pro merge that lands while the run is
queued or validating, roughly 20 minutes, makes the refusal certain.
The convergence caller treated it like any other failure, so the
release stayed off the Pro broker until the hourly reconcile happened
to retry. That race caused five of the last six Pro promotion failures
(12, 17 and 24 October); on 24 October it held v6.6.0-rc.6 back from
Pro installs on the RC channel.

The refusal happens before credentials, so nothing was mutated. The
caller now re-dispatches on the new main when every failed job failed
only the source check and pulse-pro main has moved off the run's head,
up to five attempts in the existing one-hour budget. Every other
failure stays terminal, and only the terminal failure is annotated so
reconciliation still finds exactly one private run URL.
2026-10-24 12:12:46 +01:00
pulse-triage[bot] 6908557c24 Make synthetic log-reader survival failures attributable (#3195)
Enforce the captured-reader check in the shared fixture, not only
byte-bound callers. Observe exit through its identity-checked pidfd,
retain the 500 ms bound and recheck the final boundary without another
delay. A survivor still fails after separately observed emergency
cleanup, reporting the copied-shell exit and reader state without log
bytes.

Exercise a deliberately leaked synthetic reader, last-boundary exit, PID
reuse and unavailable cleanup. The historical Docker stderr failure
remains unexplained; no copied recipe, privacy/byte/deadline limit or
rendered help changes.

Contract-Neutral: Test fixture observation and diagnostics only;
documented readers, runtime and public contracts are unchanged.

---
Fleet candidate `20261024T093936Z-web-product` from the `web-product`
lane. Reviewed tip `c83df572334b19e5dde668088e763dc57489701a` on `main`.

[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
2026-10-24 10:52:27 +00:00
pulse-triage[bot] fbe410e244 Compose chart SLO repair without dropping current administrative guarantees
Resolve adjacent contract append conflicts by keeping bounded hosted-agent classification in its chart section and preserving all newer SSO, RBAC and uninstall guarantees. Runtime, workflow and synthetic chart controls merge without conflict; no latency budget or customer journey changes.

Change-source: pulse-maintainer
2026-10-24 11:42:23 +01:00
rcourtman c7ac6ac86a Pin the Pro promotion terminal annotation where it now lives
The promotion caller now owns the terminal failure annotation, so a
re-dispatched refusal leaves none behind. The release-asset contract
test still pinned the old annotation inside wait_for_workflow. It now
pins the caller's annotation and the source-check refusal gate.
2026-10-24 11:42:17 +01:00
rcourtman ca3812e5ed Treat a deleted convergence owner as terminal
The hourly "Reconcile release convergence debt" job has failed every run
since 13 Oct. The v6.5.0 activation marker names convergence run
37395942598 as its owner, and that run was deleted from Actions with the
rest of the 30 Sep - 8 Oct release history. The immutable marker outlives
Actions history, so the reconciler and release-convergence.yml both waited
forever on an owner that can no longer be read, and the permanently red
job hid real failures such as the rc.6 paid-broker miss.

GitHub only deletes a run that has completed or is older than two weeks,
which is beyond every convergence job timeout, so a definite 404 is a
terminal owner. Both the reconciler and the successor's adoption wait now
proceed from the validated marker in that case. Any other read failure
still waits or fails.

Also remove the workflow_run retry job. Convergence runs are dispatched
with GITHUB_TOKEN, and GitHub does not deliver workflow_run for them: the
job fired seven times ever, each for a run an operator started by hand,
and never after 29 Aug while dozens of bot-dispatched failures were
recovered by the hourly schedule. The schedule is documented as the retry
mechanism.

v6.5.0 is served on every surface (Docker aliases at the marker digest,
Helm index entry, paid broker, demo /api/version), but no convergence run
has proved it. The next scheduled pass dispatches a fresh v6.5.0
convergence; its demo surface will fail until the Tailscale OAuth client
behind TS_OAUTH_CLIENT_ID/TS_OAUTH_SECRET is rotated, as it returns 401.
2026-10-24 11:40:23 +01:00
rcourtman 2d498a35d2 Re-dispatch Pro promotion refused by a moved pulse-pro main
pulse-pro gives a promotion run credentials only while that run is
still its current main. Any pulse-pro merge that lands while the run is
queued or validating, roughly 20 minutes, makes the refusal certain.
The convergence caller treated it like any other failure, so the
release stayed off the Pro broker until the hourly reconcile happened
to retry. That race caused five of the last six Pro promotion failures
(12, 17 and 24 October); on 24 October it held v6.6.0-rc.6 back from
Pro installs on the RC channel.

The refusal happens before credentials, so nothing was mutated. The
caller now re-dispatches on the new main when every failed job failed
only the source check and pulse-pro main has moved off the run's head,
up to five attempts in the existing one-hour budget. Every other
failure stays terminal, and only the terminal failure is annotated so
reconciliation still finds exactly one private run URL.
2026-10-24 11:07:44 +01:00
rcourtman 18611ec79c Refuse Unraid uninstall while the rc.local go shell is live (#3191)
Uninstall on Unraid refuses while a live go shell exists, because that
shell may still hold later boot lines in memory. Stopping the watchdog
would release it to run them. Commit 5dad231852 added that refusal, but
its check looked only for `/boot/config/go` in a process named like a
shell.

Unraid's `rc.local` never runs that path. From unraid/webgui
`etc/rc.d/rc.local` ("Invoke the 'go' script"):

```
fromdos <$CONFIG/$GO >/var/tmp/$GO
chmod +x /var/tmp/$GO
/var/tmp/$GO
```

`$GO` is `go`, or `go.safemode` in safe mode. Because the copy is
executed directly, the kernel names the process after the script. On
pulse-dev (Linux 6.8) a shebang script run that way shows `comm=go` and
`args=/bin/bash /var/tmp/go`, so the old check never matched. Hosts
installed before #3162 still have that shell blocked on the old
foreground `bash <wrapper>` line. On those hosts uninstall treated it as
unrelated, stopped the watchdog, and let go run the rest of its script.

## Change
- `read_nas_agent_removal_processes`: on Unraid, a process named `go` or
`go.safemode`, or a shell, that has `/boot/config/go`, `/var/tmp/go` or
a `.safemode` form as a whole argument is an unknown boot owner. This
replaces the old substring match, so near-miss paths
(`/var/tmp/gopher.sh`, `/boot/config/go~`) no longer block removal. A Go
toolchain process named `go` still reads as `other`.
- `agent_nas_teardown.py`:
`test_live_unraid_boot_shell_is_unknown_not_a_signal_target` now also
covers the rc.local spellings (`go /bin/bash /var/tmp/go`, `go.safemode
/bin/bash /var/tmp/go.safemode`). Every model `ps` read also includes a
Go toolchain process, so every passing Unraid control shows that process
does not block removal.
- `TestInstallSHNASRemovalTreatsLiveUnraidGoShellAsUnknownOwner`: a role
table for Unraid and QNAP run through the real function.
- agent-lifecycle and deployment-installability contracts: "Unraid/QNAP
removal" sections updated.

## Verification (pulse-dev)
- `TestInstallSHNASBootOwnersQuiesceBeforeRecoveryErasure`, the new role
test and `TestInstallSHUnraidGoEntry*` pass.
- With `origin/main`'s `install.sh` restored, the new role test and the
rc.local subcases of the live-shell control fail.

## Not covered
A go file without a `#!` line still escapes. Bash runs it in a forked
copy of `rc.local`, which keeps rc.local's name and arguments. Stock
Unraid go files start with `#!/bin/bash`. The contracts state this
limit.
2026-10-24 10:52:43 +01:00
pulse-triage[bot] c83df57233 Make synthetic log-reader survival failures attributable
Enforce the captured-reader check in the shared fixture, not only byte-bound callers. Observe exit through its identity-checked pidfd, retain the 500 ms bound and recheck the final boundary without another delay. A survivor still fails after separately observed emergency cleanup, reporting the copied-shell exit and reader state without log bytes.

Exercise a deliberately leaked synthetic reader, last-boundary exit, PID reuse and unavailable cleanup. The historical Docker stderr failure remains unexplained; no copied recipe, privacy/byte/deadline limit or rendered help changes.

Contract-Neutral: Test fixture observation and diagnostics only; documented readers, runtime and public contracts are unchanged.
Change-source: pulse-maintainer
2026-10-24 10:49:27 +01:00
pulse-triage[bot] b25c22c00f Keep bounded hosted provisioning overhead in chart SLO verdicts
Retained hosted samples include both an over-budget failure and an under-budget pass with one provisioning agent occupying about one logical CPU. Attribute only that bounded Actions overhead; retain raw CPU and absolute 90 ms latency, and keep other or unattributed CPU, guest, steal and swap invalidating. Exercise the real CLI and workflow shells with adverse controls; no timed workload or release acceptance is claimed.

Change-source: pulse-maintainer
2026-10-24 10:48:40 +01:00
rcourtman 27f7e11e9b Refuse Unraid uninstall while the rc.local go shell is live
Uninstall treats a live Unraid go shell as an unknown boot owner and
refuses, because that shell may still hold later boot lines in memory.
Signalling the watchdog would release it to run them. The check only
looked for /boot/config/go in a process whose name is a shell. Unraid's
rc.local never runs that path: it writes a fromdos copy to /var/tmp/go
(go.safemode in safe mode) and executes that copy directly. The kernel
then names the process "go", with argv "/bin/bash /var/tmp/go", so the
check never matched it.

Hosts installed before the detached go entry still have this shell
blocked on the old foreground wrapper line. On those hosts uninstall
classified the shell as unrelated, stopped the watchdog, and let go run
the rest of its in-memory script. That is the case the live-shell
refusal was added to prevent.

The role check now covers a go or go.safemode process, or a shell, that
has /boot/config/go, /var/tmp/go or a .safemode form as a whole
argument. The old substring match is gone, so near-miss paths such as
/var/tmp/gopher.sh no longer block removal, and a Go toolchain process
named go still reads as unrelated. The NAS teardown control covers the
rc.local spellings, and a new role-table test pins Unraid and QNAP.
Both fail against the previous install.sh.

A go file without a #! line is still not recognised. Bash runs it in a
forked copy of rc.local, and the contracts now say so.
2026-10-24 10:26:45 +01:00
pulse-triage[bot] 58e46e21d7 Bind audit help checks to the bounded selection decoder
Repair the containing CI failure from PR 3186 without restoring last-member-wins parsing. Keep the explicit array, request bound, URL validation before mutation and organisation-scoped replacement checks; runtime selection semantics remain covered by the existing handler tests.

Contract-Neutral: Static guidance/source-binding test repair only; the composed audit runtime and documented API, access, storage and delivery contracts are unchanged.
Change-source: pulse-maintainer
2026-10-24 09:25:26 +01:00
pulse-triage[bot] ec816e8491 Reconcile the separated metrics and HTTP dependency graph
Carry the non-storage managed proposal without its checksum pruning or unrelated dependency reclassification. Update the graph admission floors and the deployment contract; exact-graph acquisition and affected runtime/build proof remain required before acceptance.

Source-PR: https://github.com/rcourtman/Pulse/pull/3181
Source-Commit: b33dee6d7f
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Change-source: pulse-maintainer
Contract-Neutral: Dependency versions and internal graph-admission floors only; no runtime API, wire format, permission, rendered state, deployment interface or installer contract changes.
2026-10-24 07:11:14 +01:00
pulse-triage[bot] 5b25d801bc Separate storage runtime dependency proposals from other Go patches
Keep modernc driver and runtime updates together while allowing unrelated minor and patch updates to progress independently. Preserve all security-update coverage and individual major updates. Add the current SQLite/libc and Prometheus grouping regression to the maintained smoke suite.

Change-source: pulse-maintainer
2026-10-24 06:17:42 +01:00
pulse-triage[bot] 53f5fceede Reconcile the non-storage managed Go dependency refresh
Select the ten outstanding non-storage updates from managed proposal 3056 and their seven transitive updates without importing its compiler downgrade, storage changes or checksum pruning. Preserve Go 1.26.10, x/net 0.60.0 and the aligned Kubernetes graph. Extend existing manifest-floor proof; exact-graph runtime acceptance remains required after dependency acquisition.

Contract-Neutral: Selected dependency versions and existing internal graph-admission floors only; no runtime API, wire format, permission, deployment interface or installer contract changes.
Change-source: pulse-maintainer
2026-10-24 04:06:14 +01:00
pulse-triage[bot] f19424f51a Complete credited chart evidence reporting on current main (#3169)
Isolate the retained PR3095 completion (7f4ec192 and 93d87118) without
importing unrelated history. Keep the exact proposed Python classifier
and maintained chart shells, real CLI/workflow controls and dependent
contracts. Inconclusive capacity never establishes the 90 ms budget;
child, cleanup and malformed-proof failures remain errors.

Source-PR: https://github.com/rcourtman/Pulse/pull/3095
Source-Commit: b31fabd778
Co-authored-by: rcourtman <8825017+rcourtman@users.noreply.github.com>

---
Fleet candidate `20261024T010002Z-delivery-trust` from the
`delivery-trust` lane. Reviewed tip
`7e7cea87a6bce2e7a2e00e888a676c571e141d92` on `main`.

[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
2026-10-24 02:26:12 +00:00
pulse-triage[bot] 7e7cea87a6 Reconcile chart reporting with current Patrol contracts
Compose retained 8478eac3 additively on current main. Preserve both independently appended contract sections at each of the three documentation conflicts; workflow, registered executable controls and classifier stay unchanged.

Change-source: pulse-maintainer
2026-10-24 02:02:24 +01:00
rcourtman 4f3e170612 Detach the Unraid boot entry so later go lines run
The Unraid installer appended `bash <wrapper>` to /boot/config/go. The
wrapper is an endless watchdog loop, so that line never returned, and
rc.local never reached anything the user had placed after the Pulse
block. On a maintainer host a reboot skipped swap, a memory logger and a
hosts entry the agent needed to reach its server, and Pulse showed the
host as down for two days while it was healthy.

The entry now backgrounds the wrapper with its output redirected, so go
returns and holds no boot output pipe open. Install-time cleanup used to
delete every go line containing "pulse-agent", including log directories,
hosts entries and a co-installed agent. It now removes only the
installer's marker and command lines that name a start-pulse-agent.sh
wrapper or this runtime binary outside a comment, so upgrades from the
foreground or hand-edited entry still leave exactly one launch. Kept
lines lose a trailing CR, as Unraid's fromdos does before running go, and
a removal that would leave go unparseable is refused with a warning.
Uninstall admits the detached entry as well as the earlier foreground
form.

The new tests execute the go file the installer writes and require it to
return, release its output pipe and run the next line, with a planted
foreground entry as the control, and pin the narrowed cleanup against
the removal filter. The NAS teardown controls now render their Unraid
entry through the same emitter.
2026-10-24 00:34:31 +01:00
rcourtman 8fc2ef2931 Remove unreferenced one-off browser proof harnesses (#3155)
Fleet lanes committed a fixture page, build script and check script
alongside each fix to prove it once in a browser. This removes the 168
such files (about 19,850 lines) that nothing in the repository names: no
subsystem contract, release verification matrix, test, workflow, package
script or live harness. Harnesses the contracts and the high-risk
verification matrix describe, and the modules they import, stay. The
browser verification guard covers `frontend-modern/src` only, so no
receipt is involved.
2026-10-24 00:26:52 +01:00
pulse-triage[bot] 8478eac3ef Complete credited chart evidence reporting on current main
Isolate the retained PR3095 completion (7f4ec192 and 93d87118) without importing unrelated history. Keep the exact proposed Python classifier and maintained chart shells, real CLI/workflow controls and dependent contracts. Inconclusive capacity never establishes the 90 ms budget; child, cleanup and malformed-proof failures remain errors.

Source-PR: https://github.com/rcourtman/Pulse/pull/3095
Source-Commit: b31fabd778
Co-authored-by: rcourtman <8825017+rcourtman@users.noreply.github.com>
Change-source: pulse-maintainer
2026-10-24 00:26:11 +01:00
rcourtman 6a45411bd1 Remove unreferenced one-off browser proof harnesses
Fleet lanes committed a fixture page, build script and check script
alongside each fix to prove it in a browser once. 168 of those files,
about 19,850 lines, are named by nothing in the repository: no
subsystem contract, release verification matrix, test, workflow,
package script or live harness. Harnesses the contracts and the
high-risk verification matrix describe, and the modules they import,
stay. The lanes no longer commit proof-only fixtures.

Contract-Neutral: removes proof fixtures no contract, registry entry or test references; no runtime or contract change
2026-10-23 23:18:30 +01:00
pulse-triage[bot] b79496219f Preserve prior installer snapshots on retry
Reconcile the retained snapshot publication repair with current main without importing unrelated containing history. Unique private staging, no-clobber publication and failure-before-mutation protect earlier recovery copies; retain zero-retention and hardened-unit fallback semantics.

Retained-source: 854ea3c81a94ffe88145d663d25d5040d4637a47, 91bd7393fc4413b6629ad851f90c2c7f6c2c0991
Change-source: pulse-maintainer
2026-10-23 22:39:08 +01:00
pulse-triage[bot] f5c2c3a198 Reproduce PVE partial-scan recovery history loss (#3148)
**Reproduce PVE partial-scan recovery history loss**

Drive ordinary backup polling through durable recovery ingest after live
inventory replacement, with partial, complete, isolation and
cancellation controls.

**Retain PVE recovery history across incomplete backup scans**

Use the poll's existing completeness evidence to admit destructive
reconciliation. Failed or skipped reads may update accepted rows without
deleting unseen durable facts, and cancellation cannot publish an empty
success. Complete deletions remain scoped and tested.

Contract-Neutral: Restore collection truth without changing APIs,
schemas, configuration or protection policy.

**Keep carried PVE rows from renewing recovery observations**

Retain their existing durable point evidence under the partial provider
observation instead of presenting a failed refresh as a fresh artifact
observation. Cover warm inventory alongside the cold-start
reconciliation regression.

Contract-Neutral: No API, schema, configuration or protection-policy
delta.

**Match the full workload identity in the PVE browser journey**

Use the production disclosure's guest name and VM identity, and bring
its provider evidence into the captured viewport. The initial selector
timeout is retained as a harness failure, not a product result.

**Avoid the published monitoring contract insertion conflict**

Relocate the PVE partial-backup collection contract without changing its
text so it composes with the published snapshot-listing contract at
15ea29fe2b. Runtime, regression tests and
browser-proof inputs remain unchanged.

---
Fleet candidate `20261023T194015Z-core-runtime` from the `core-runtime`
lane. Reviewed tip `d39d65fede2a6afc535c0387b0c0e6683868b22e` on `main`.

[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
2026-10-23 20:48:34 +00:00
pulse-triage[bot] 15ea29fe2b Cover failed snapshot listings without treating errors as deletion (#3146)
**Cover failed snapshot listings without treating errors as deletion**

Exercise both guest kinds, partial error results, same-VMID peer
isolation, warning continuity, accepted removal and explicit disablement
through the actual monitor. Include opt-in synthetic frames for the
production alert consumer.

**Use the served alert model in snapshot collection proofs**

The monitor exposes models.Alert, not the internal manager alert type.
Correct the fixture-only type mismatch before establishing the
unchanged-runtime control.

**Keep known LXC snapshots when their listing is unavailable**

Treat every failed snapshot read as incomplete rather than interpreting
596 or unavailable text as an empty successful listing. Preserve known
membership and warnings while independent accepted listings and
confirmed removal continue normally. Correct the isolation fixture to
use cluster-unique VMIDs, keeping the same-VMID cross-instance control.

Contract-Neutral: Restores existing failed-listing semantics for LXC; no
public API, schema, configuration, identity or alert policy delta.
Dedicated collection and producer/browser regressions are outside the
registry's fixed verification filenames.

---
Fleet candidate `20261023T190018Z-core-runtime` from the `core-runtime`
lane. Reviewed tip `850a6310446030354d29787b84e794e0b37852db` on `main`.

[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
2026-10-23 20:04:35 +00:00
pulse-triage[bot] 7054346af9 Match the full workload identity in the PVE browser journey
Use the production disclosure's guest name and VM identity, and bring its provider evidence into the captured viewport. The initial selector timeout is retained as a harness failure, not a product result.

Change-source: pulse-maintainer
2026-10-23 21:03:01 +01:00
pulse-triage[bot] 10f570a698 Keep carried PVE rows from renewing recovery observations
Retain their existing durable point evidence under the partial provider observation instead of presenting a failed refresh as a fresh artifact observation. Cover warm inventory alongside the cold-start reconciliation regression.

Contract-Neutral: No API, schema, configuration or protection-policy delta.
Change-source: pulse-maintainer
2026-10-23 20:50:06 +01:00
pulse-triage[bot] 50abcf51c4 Retain PVE recovery history across incomplete backup scans
Use the poll's existing completeness evidence to admit destructive reconciliation. Failed or skipped reads may update accepted rows without deleting unseen durable facts, and cancellation cannot publish an empty success. Complete deletions remain scoped and tested.

Contract-Neutral: Restore collection truth without changing APIs, schemas, configuration or protection policy.
Change-source: pulse-maintainer
2026-10-23 20:46:39 +01:00
pulse-triage[bot] 850a631044 Keep known LXC snapshots when their listing is unavailable
Treat every failed snapshot read as incomplete rather than interpreting 596 or unavailable text as an empty successful listing. Preserve known membership and warnings while independent accepted listings and confirmed removal continue normally. Correct the isolation fixture to use cluster-unique VMIDs, keeping the same-VMID cross-instance control.

Contract-Neutral: Restores existing failed-listing semantics for LXC; no public API, schema, configuration, identity or alert policy delta. Dedicated collection and producer/browser regressions are outside the registry's fixed verification filenames.
Change-source: pulse-maintainer
2026-10-23 20:14:11 +01:00
pulse-triage[bot] 9b607668b9 Compose snapshot warning preservation with current backup-date repair
Resolve the shared contract insertion by retaining both complete subsections. Preserve the reviewed snapshot creation-date repair and current main's independent backup success-date repair, tests and fixtures.

Contract-Neutral: Compose existing snapshot and backup warning preservation repairs without changing their public API, configuration, schema or canonical identity contracts. Retain both internal contract clarifications and executable verification.\nChange-source: pulse-maintainer
Change-source: pulse-maintainer
2026-10-23 19:42:00 +01:00
pulse-triage[bot] 9fb404604b Core runtime and integrations (#3143)
Improvement: backup-age false-recovery repair now has executable and
desktop/phone pixel proof.

**Continuation — truthful monitoring and backup evidence.** Candidate
**6fb43d9302d6673bc65193f3e17944098394ad6d**, above **c67f8bd500**,
contains **208f0cbf1e** plus an additive fixture correction.
Original-runtime control reproduces false recovery; full alert race/vet,
final consumer type checks, **1,404 tests**, compiled real Overview and
both browser journeys pass. Complete output hashes match, source guests
stopped, and all eight captures were natively opened and inspected.
Coordinator/reviewer/publisher own containing CI, independent review and
landing; their containing result or repair return is next. **Not landed,
released or installed recovery.** [Receipts](RECEIPTS.md),
[source](SOURCE.json), [continuation](CONTINUATION.json).

This raises the highest-ranked **guest/backup safety** weakness: a
still-listed backup's missing/zero/future date no longer clears an
established warning or hides valid provider evidence. Last trusted
occurrence/evidence survives; valid recent success, exclusions and
authoritative removal still clear normally. The executed baseline
establishes the defect, not a field incident's cause or native thaw
safety. [Reproduction](REPRODUCTION.json), [scope and original
jobs](RECONCILIATION.json).

The first consumer proof exposed a fixture-only type error; the additive
correction uses the current AI capability store without changing
production code or weakening checks. Both commits pass canonical
preflight; the frontend-file guard skip is not the separately completed
browser proof. [Validation](VALIDATION.json), [adverse
evidence](ADVERSE.json), [pixels](PIXEL-REVIEW.json).

Received continuations **416bb1c9 / 58e731f1** are completed at the
source-validation step. Previous node candidate **3c66ab14e7** and
Delivery/Pro/Host/PI's original installed guest, dashboard, SSO and
notification recoveries remain separately retained. No duplicate
handoff, infrastructure, guest probe, excluded investigation, release or
public action.

---
Fleet candidate `20261023T172026Z-core-runtime` from the `core-runtime`
lane. Reviewed tip `6fb43d9302d6673bc65193f3e17944098394ad6d` on `main`.

[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
2026-10-23 18:15:24 +00:00
pulse-triage[bot] d07080e8fb Keep snapshot warnings when creation dates are unknown
Distinguish a listed snapshot with an unusable date from removal. Retain the last trusted canonical occurrence and evidence after current policy resolution, including Proxmox's missing-snaptime Unix epoch representation. Add lifecycle, exclusion, identity and real-consumer browser proof fixtures.

Contract-Neutral: Repair existing snapshot warning preservation on incomplete evidence; no API, configuration, schema or canonical identity change. Dedicated regression and browser-producer tests accompany the internal contract clarification.
Change-source: pulse-maintainer
2026-10-23 18:59:08 +01:00