Commit Graph

656 Commits

Author SHA1 Message Date
rcourtman 9e99c18c6f Align agent auth documentation checks with route authority 2026-10-26 22:25:11 +00:00
pulse-triage[bot] 071dadf1f7 Exercise balanced smoke selection through the workflow fixture
Copy the real selector and its timing hints into the existing whole-inventory workflow fixture. Verify sorted, disjoint complete coverage and inject a failure into each actual selected shard, keeping the required verdict fail closed instead of asserting the retired filename-parity placement.

Contract-Neutral: Consuming CI fixture alignment for whole-suite scheduling only; workflow admission, check names, runtime tests and acceptance remain unchanged.
Change-source: pulse-maintainer
2026-10-26 17:36:56 +00:00
pulse-triage[bot] db76f62798 Balance isolated smoke suites with measured scheduling hints
A complete passing PR run spent 318 and 567 seconds inside the two smoke inventories. Filename parity places the long deadline controls together. Partition every discovered suite by measured duration while preserving sorted per-shard execution, real deadlines, failure collection and the existing checks. New suites use a default weight; stale hints cannot add or omit coverage, and incomplete selection fails before execution.

Contract-Neutral: CI scheduling of unchanged complete script suites only; product, installer, release and verification acceptance contracts are unchanged.
Change-source: pulse-maintainer
2026-10-26 17:32:06 +00:00
pulse-triage[bot] 5cf7d82c6a Bound synchronous audit exports and summaries
Limit the actual query to 10001 rows and refuse selections over 10000 before verification or encoding. Preserve complete accepted results, selectors, signatures and access boundaries, and explain how to narrow a refused selection.

Change-source: pulse-maintainer
2026-10-26 16:06:56 +00:00
pulse-triage[bot] aaf38867e7 Recover lifecycle discovery from peer stream cancellation
The daily install/recovery rehearsal stopped before installation in run 40343060586 when GitHub cancelled a metadata stream. Retry only that exact transport-only exit, with fixed GET identities, deadlines and a finite budget; discard partial output and stop on refusals, malformed data, signals or unknown errors.

Exercise the actual workflow resolver with synthetic process outcomes and retain the existing signed installation, update and rollback contracts. This changes no release gate or deployment operation.

Change-source: pulse-maintainer
2026-10-26 14:57:25 +00:00
rcourtman d5604fe3df Confine release credentials to the release environment (#3303)
## What

Every job that reads a release, signing or registry credential now
declares
`environment: release`, and `scripts/check_workflow_trust.py` enforces
it.

- 20 jobs across `create-release`, `build-release-candidate`,
`publish-docker`,
  `promote-floating-tags`, `promote-private-pro-runtime`,
  `recover-release-activation`, `backfill-release-assets`,
  `retry-release-convergence`, `release-signing-preflight`,
  `signpath-test-signing` and `canonical-private-governance` declare
`environment: release`. `qualify-browser-update-release` declares
`infra` for
its tailnet credentials. `PULSE_LICENSE_PUBLIC_KEY` is a public key and
stays
  repository-wide.
- The checker reads job structure with a duplicate-key-rejecting YAML
loader
  and scans both raw text and decoded values for secret expressions
  (case-insensitive, across lines, quote-aware). It requires the literal
release environment for release credentials and a deployment environment
for demo/tailnet credentials (the demo workflow's runtime choice only in
its
own job). It refuses dynamic `secrets[...]` access and workflow-level
secret
env, and requires any push workflow that reads a secret to admit exactly
  `branches: [main]`.

## Why

Release secrets are repository-level today, so any workflow run on any
branch,
including a pushed proposal branch before review, can read them. The
release
train is switching to post-merge `release-dispatch/*` branches that only
the
release dispatcher App can create (ruleset-enforced). A `release`
environment
admitting only `main` and `release-dispatch/*` then keeps these
credentials
away from unmerged code.

## Merge order (draft until then)

Stacked on #3297. Do not merge until:
1. a beta has published through a `release-dispatch/*` dispatch, and
2. the `release` (branches `main`, `release-dispatch/*`) and `infra`
(`main`)
environments exist with branch-typed policies, so the first post-merge
run
   does not auto-create an unprotected environment.

Repository-level secret copies stay until no snapshot without these
declarations can still be dispatched or recovered.

## Validation

- Live tree passes the checker; `test_workflow_trust.py` 50 OK,
including new
cases for every rule and for bypasses found in review (lower-case names,
`}}` inside strings and YAML-escaped quotes, `release#x`, duplicate
keys,
  quoted `tags`/`inherit`, a push key hidden in a description, the demo
  expression outside its job).
- Eleven mutations, one per guard, each fail the tests.
- All 1301 `scripts/tests`, Go `scripts/installtests`, and
`release_promotion_policy_test.py` 74 OK (new proof test pins the
release
jobs' environment). Release-control discovery has 17 failures and 1
error
  that are identical on `main` and on this branch's base.
2026-10-26 14:22:52 +00:00
pulse-triage[bot] 34e3502630 Separate PMG decoding failures from gateway reachability
Explain the queue-response failure reported on stable without treating an unread dataset as an empty queue or an authentication failure. Keep native queue monitoring and private, bounded evidence as the fallback rather than DNS, privilege or mail mutations.

Contract-Neutral: Existing PMG help and safety regression coverage only; no collector, API, schema, permission or navigation behaviour changes.
Change-source: pulse-maintainer
2026-10-26 10:21:04 +00:00
rcourtman 9406ceb23e Name workflow trust test inputs as references
CodeQL flagged the release_job helper as clear-text storage of a secret because its parameter was named secret. The value is only the ${{ secrets.NAME }} expression text written into a fixture workflow, never a credential, so the name now says that.
2026-10-26 08:47:48 +00:00
pulse-triage[bot] 3bb2c7e95d Pin installer help to its verified private-file guide
The returned candidate failed the existing branch-tip documentation guard in script smoke shard 0. Keep that guard intact, bind help to the inspected immutable guide, and test the real emitted URL as well as the private-file commands.

Contract-Neutral: CLI guidance and its regression only; installer flags, authentication, TLS, service lifecycle and runtime behaviour are unchanged.
Change-source: pulse-maintainer
2026-10-26 08:40:58 +00:00
pulse-triage[bot] 2b0b134dfa Keep agent installer guidance off token arguments and HTTP pipes
Recommend the existing inspected HTTPS/private-file route in shipped help and the source header. Exercise copied commands, saved-state updates and side-effect-free help with synthetic credentials.

Contract-Neutral: CLI guidance only; installer flags, authentication, TLS, service lifecycle and runtime behaviour are unchanged.
Change-source: pulse-maintainer
2026-10-26 07:37:06 +00:00
rcourtman 69354b9d20 Confine release credentials to the release environment
Release, signing and registry secrets are repository-wide, so a workflow run
on any branch can read them, including a pushed proposal branch before any
review. The release train now dispatches on post-merge release-dispatch/*
branches that only the release dispatcher App can create, so these secrets
can move into a `release` environment that admits only main and those
branches.

Every job that reads the update signing key, Apple, SignPath or Windows
signing material, Docker Hub credentials or WORKFLOW_PAT now declares
`environment: release`; the browser update qualification job declares `infra`
for its tailnet credentials. The public license verification key is not a
credential and stays repository-wide.

check_workflow_trust.py enforces this. It reads job structure with a YAML
loader that rejects duplicate keys and scans expressions across lines,
comments and quoted `}}`, matching secret names case-insensitively. Release
credentials need the literal release environment, demo and tailnet
credentials need a deployment environment (the demo workflow's runtime choice
only in its own job), dynamic secrets[...] access and workflow-level secret
env are refused, and a push workflow that reads any secret must admit exactly
`branches: [main]`. A test that asserted an any-branch push workflow could
read WORKFLOW_PAT now asserts the opposite.
2026-10-26 00:30:23 +00:00
pulse-triage[bot] af5b66dad8 Align triage disclosure with current release and retest policy (#3296)
**Align triage disclosure with current release and retest policy**

Correct the disclosure linked from every community reply and its shipped
Docs copy: weekly stable targets, daily betas instead of early candidate
cuts, and the stable publication clock when a same-fix preview retest
already exhausted unanswered contact. Correct the linked release guide
as well, preserving every-symptom resolution, safe retesting and
unchanged candidate soak. Add registered document and
production-renderer coverage.

Contract-Neutral: Public guidance now matches existing standing release
and contact policy; no runtime, release machinery, authority or
subsystem contract change.

**Explain CORE reporting rejection without repeated capture**

Distinguish the reported HTTP 400 query-schema failure from an invalid
API key, refreshed inventory and measured idle zeros. Link
missing-telemetry readers to the safe native Reporting fallback before
more capture, retaining the original report and upgrade relevance. Add
registered production-renderer regression coverage.

Contract-Neutral: Existing TrueNAS troubleshooting guidance only; no
API, collector, storage, permission or release contract change.

**Assert the native fragment contract for CORE help**

The first source proof caught a test-only assumption: fragment-only
links deliberately use native browser anchors, not the cross-document
router marker. Check that existing contract; the guide bytes are
unchanged. Retain the original failed proof.

Contract-Neutral: Correct a documentation test assertion; no runtime or
subsystem contract change.

**Format issue follow-through renderer tests for CI**

The reviewed help candidate failed the required full frontend formatting
check because its disclosure test file was not included in the focused
formatting command. Apply the configured style without changing
assertions, documentation or runtime behaviour.

Contract-Neutral: Test-only formatting; no rendered content, runtime or
subsystem contract changes.

**Finish formatting long disclosure assertions**

The full-tree check found additional over-width assertions beyond the
first scoped repair. Reflow the remaining expressions without changing
their tokens or documentation.

Contract-Neutral: Test expression layout only; assertions and runtime
behaviour are unchanged.

---
Fleet candidate `20261025T210853Z-product-intelligence` from the
`product-intelligence` lane. Reviewed tip
`b06f1584aa8da42d3effbae4c57e7b8c325c5d57` on `main`.

[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
2026-10-25 22:53:16 +00:00
rcourtman b3a27e2dd2 Sync issue labels with GITHUB_TOKEN, not the triage App key
The label sync was the only workflow that read PULSE_TRIAGE_APP_PRIVATE_KEY.
That key belongs to an App installation that can administer the repository,
and as a repository-level Actions secret any workflow run on any branch could
read it. Everything the helper does (read the issue, create, add and remove
labels) is covered by the run's own GITHUB_TOKEN with issues: write, so the
App key can now be deleted from Actions.

The policy test now requires issue-mutating workflows to use the scoped
GITHUB_TOKEN and to reference no secrets, and still requires the parser tests
to run before the label write. Silent labels are applied as
github-actions[bot]; AI_TRANSPARENCY.md says so.
2026-10-25 21:21:54 +00:00
pulse-triage[bot] 6d3315934b Merge retained CORE and triage help corrections for CI repair
Change-source: pulse-maintainer
2026-10-25 21:10:33 +00:00
pulse-triage[bot] 21a32dbf86 Fail closed when local pre-push source reads fail
Require complete Git scope, parent, trailer and file observations before checking committed source. Keep ordinary dirty-tree exits distinct from read errors, retain every failing canonical commit, and stop before expensive source checks when admission is already blocked. Fault-injection controls exercise empty and partial reads alongside the successful Go, type-check and browser-guard path.

Contract-Neutral: Local pre-push orchestration only; product contracts and the required source, audit and browser checks are unchanged.
Change-source: pulse-maintainer
2026-10-25 19:47:30 +00:00
pulse-triage[bot] 3fb0ec966f Merge commit 'f7cd68379b00266870a6345a9ebbd55fd5b75c40' into maintainer-async/20261025T184637Z-product-intelligence/pulse
Change-source: pulse-maintainer
2026-10-25 19:20:08 +00:00
pulse-triage[bot] f7cd68379b Align triage disclosure with current release and retest policy
Correct the disclosure linked from every community reply and its shipped Docs copy: weekly stable targets, daily betas instead of early candidate cuts, and the stable publication clock when a same-fix preview retest already exhausted unanswered contact. Correct the linked release guide as well, preserving every-symptom resolution, safe retesting and unchanged candidate soak. Add registered document and production-renderer coverage.

Contract-Neutral: Public guidance now matches existing standing release and contact policy; no runtime, release machinery, authority or subsystem contract change.
Change-source: pulse-maintainer
2026-10-25 16:28:47 +00:00
pulse-triage[bot] 89c61b233c Keep signed manual update bootstraps on HTTPS
The generated manual helper currently permits an HTTPS asset redirect to plaintext HTTP, unlike the unattended downloader. Restrict initial and redirect protocols for both signed inputs, without weakening deadlines, signature verification or cleanup. Exercise the actual helper with real curl and authenticated local TLS, including downgrade refusals and permitted HTTPS redirects; keep the native systemd fixture on the exact envelope.

Change-source: pulse-maintainer
2026-10-25 15:47:43 +00:00
pulse-triage[bot] 296b128254 Interpret byte-throughput benchmark changes in the right direction
SetBytes benchmarks report B/s beside time and allocation costs. Treat lower byte throughput as adverse, retain lower-is-better cost metrics, and include each finding's unit so scaled values are not ambiguous. Keep the significance, sample and magnitude gates unchanged.

Contract-Neutral: CI benchmark verdict parsing and registered regression controls only; no product runtime or subsystem contract change.
Change-source: pulse-maintainer
2026-10-25 11:25:52 +00:00
pulse-triage[bot] e404c2fe07 Keep isolated issue-triage changes on their dedicated CI path
The proposed-source triage suite already exercises the locked parser and silent-mutation consumers. Pure helper edits still queued unrelated application suites for more than twenty minutes. Recognise only the six exact triage inputs from a complete tree diff; mixed, missing and control-path changes retain full application checks. Keep workflow output outside the fixture source tree so real-diff controls do not stage it.

Contract-Neutral: CI admission for isolated issue-event inputs only; locked triage tests, secret scanning, governance and mixed-source runtime checks remain enforced, with no product contract or permission change.
Change-source: pulse-maintainer
2026-10-25 09:04:08 +00:00
pulse-triage[bot] 5d748986b3 Keep native recovery proof aligned with bounded manual downloads
Admit only the manual helper's exact new curl envelope in the existing closed transport fixture. Require a signed emitted-helper round trip and reject altered deadlines, retries and TLS flags through the registered installer suite; do not widen the adapter or execute a native journey.

Change-source: pulse-maintainer
2026-10-25 06:38:18 +00:00
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
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
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
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] 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] 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
rcourtman d2ac07bccf Cache browser OS packages so slow apt mirrors stop E2E
Since 22 October the E2E jobs often time out installing browsers before
any test runs: 29 installs failed that day and 30 on 23 October, against
none in the week before. Each job downloads about 119 MB of Ubuntu
packages for Chromium and WebKit from the runner's Azure mirror, and
some GitHub-hosted runners now get tens of kB/s from it
(actions/runner-images#14823 and #15040). The same package set on the
same image versions installed in under a minute before then.

The three browser jobs now restore the newest saved .deb set with
actions/cache/restore and admit it through scripts/browser_os_packages.py.
apt reuses a file already in its archive directory after checking only
its size, so the helper refreshes the index and installs a private copy
of a cached file only when that copy's SHA256 matches a signed index
stanza for the package, version and architecture its filename names.
After a successful install, and before any journey can fail the job,
the helper rebuilds the cache from apt's archives and the job saves it
under a run-unique key only when the set changed, so Ubuntu updates
refresh the cache and an empty or unchanged set is never saved.

The transport bounds and install budgets are unchanged, and the jobs
hold no secrets or write tokens, as the workflow trust contract requires
for caches.
2026-10-23 18:02:39 +01:00
courtmanr@gmail.com b08fbd8a24 Match the Mail Gateway window check to the shared drawer
The PMG help says to compare the same time window in PMG, and its docs
check pinned the old drawer's `stats()?.timeframe` read. The Mail tab is
now headless mail-flow content inside the shared resource drawer and
names the window on its Mail flow card from the same field
(`stats?.timeframe`); the check now accepts either spelling, so the
help still has to describe a window the drawer actually shows.
2026-10-22 17:00:53 +01:00
courtmanr@gmail.com 345babc6a8 Record the Kubernetes chunk size and new record drawer labels
The Kubernetes events, ConfigMap/Secret/RBAC and policy rows now build
record drawers in the page chunk, which measures 21732 bytes gzipped on a
fresh build of this branch. Its recorded baseline (18267) predated
earlier growth on the Kubernetes tabs, so the chunk crossed its limit by
0.71 kB. Lazy-loading the record panels was tried and made the chunk
larger (their shared pieces already live in common chunks), so this
records the measured size and leaves every other chunk's baseline
unchanged.

Two docs checks pinned the old hand-written markup: replication help
matched `>Guest</dt>`-style labels, and Agent Doctor help matched a
"· Privilege:" sentence fragment. The same labels are now shared detail
rows and section labels; the checks match those, so the help still has
to name labels the drawers actually show.
2026-10-22 15:33:15 +01:00
rcourtman 46a87e1a46 Point localized READMEs at the current licence screen
The German and Spanish getting-started guides told paid customers to
activate under Settings -> Plans -> Existing purchases. That heading
left the app in June (27ba85ddc6); the key field now sits under
Settings -> Plans & Billing -> License recovery, so customers following
the guide looked for a section that does not exist. Update both guides,
their shipped mirrors, and the machine-facing string the localized docs
test pins.
2026-10-22 11:00:31 +01:00
rcourtman 02e53bc777 build: move to Go 1.26.10 and Vite 6.4.5 for October advisories
Go 1.26.10 (20 October) distrusts the compromised eMudhra intermediate
CAs in crypto/x509 (CVE-2026-111943). Binaries built with 1.26.9 still
accept chains through them, so every verified outbound TLS connection
Pulse makes (licence, updates, webhooks, AI providers) stays open to
interception by a holder of those keys. govulncheck does not flag a
trust-store change as a called symbol, so the scheduled scan stayed
green while the gap existed.

Advance the governed toolchain floor and every pin together: go.mod,
the toolchain installer and release-script guards, the source-built
container stages (manifest-list digests for golang:1.26.10-alpine and
the Debian dev container image), the root-pair diagnostic, and their
tests.

Vite 6.4.3 bundles a launch-editor with three advisories
(GHSA-587h-7wmj-h5pm, GHSA-r825-w8mm-5pxw, GHSA-698v-4r3x-3vcv) that
failed the daily advisory watch. 6.4.4 bundles the fixed launch-editor
and 6.4.5 adds the dev-server server.fs query check. Both reach only
the local dev server, not the built product. The lockfile changes only
the vite entry, and dependencySecurity.test.ts now pins the floor.
2026-10-21 15:19:02 +01:00
rcourtman 266144de1f Share native installer execution controls with script smoke tests
Script smoke still asserted the removed grouped runner while native
verification used a separate suite. Share the canonical execution controls
so both entrypoints reject lost checks, false passes and changed deadlines.
2026-10-18 17:55:06 +01:00
rcourtman 2fc54a5a1f Merge pending maintenance repairs with current main
Preserve selected memory freshness and the VM/LXC interpretation.
Retain both native tool contracts and current API concurrency controls.
Qualify this source separately from release and installed recovery.

Contract-Neutral: Integrate already-governed parents without a new contract change. Incoming verification files already match main. Fresh integration tests and source-bound browser proof cover the combined memory and installer surfaces.
2026-10-18 15:11:28 +01:00
courtmanr@gmail.com 92b784bef2 Keep reliability checks tied to workflows and selected tools
Require the existing troubleshooting jobs and their destinations without
making additional help entries break unrelated safety checks. Keep the
opening backup warning scoped to its actual entry point.

Run closed service and middleware models through the containing fixture's
selected Python interpreter without site startup. Retain every safety
scenario and deadline while qualifying the pending maintenance source.

Refs #2888

Contract-Neutral: Test-only navigation assertions and confined model interpreter selection. Production behavior and safety deadlines are unchanged.
2026-10-18 14:28:37 +01:00
courtmanr@gmail.com 7e502b5c92 Separate reporting generation days from successful repeat periods
A scheduled retry across UTC days can generate another artifact without
completing a new successful reporting period. Keep multi-day generation as
an activity observation rather than inferred repeat use, while retaining
successful distinct-period counts as their own signal.

Exercise both cross-day generation without success and multiple successful
periods on one day so the adoption summary cannot conflate these metrics.
2026-10-17 21:51:08 +01:00
rcourtman a224a1a195 Measure aggregate reporting outcomes and repeat use
Record successful response writes, scheduled generation, file saves and SMTP
outcomes in a durable content-free tally. Distinct active days include manual
exports, while saved-schedule periods deduplicate retries and monthly reuse.

Publish bounded scalars through the existing opt-out-controlled heartbeat and
report missing coverage explicitly. Preserve pricing and customer entitlements.
2026-10-17 21:10:17 +01:00
rcourtman 78301b91ed Teach route checks and contracts about RequireOrgAdmin
The route inventory treated RequireOrgAdmin routes as unauthenticated
"bare" routes, and the agent diagnostics contract and the API
reference anchors still named RequireAdmin for routes that now opt
into organization authority. The security-privacy contract still said
org managers receive reportingRead through ensureAdminSession; it now
names the org-bound routes' check and records that instance
administration refuses organization owners. The agent-lifecycle
contract notes that agent routes declare that authority explicitly.
2026-10-17 10:24:15 +01:00
rcourtman 7c29ec63e3 Read agentless LXC listing memory as real pressure in Patrol (#3021)
Commit a5baa7563b stopped Patrol reading cache-inclusive Proxmox memory
as guest pressure (issue #2762, a QEMU VM). It also put
`cluster-resources` in that cache-inclusive group for every guest type.
An LXC without a linked Pulse agent only ever gets `cluster-resources`,
so Patrol dropped memory pressure for all agentless containers:
- a container at 97% of its limit got no triage flag, forecast or
anomaly
- the seed said "guest pressure unknown; may include reclaimable cache"
- older memory alerts went to a billed model review on every run, and
any resolve verdict was thrown away

**That premise is wrong for LXC.** On both PVE 9 (`master`) and PVE 8
(`stable-bookworm` / `stable-8`), Proxmox subtracts page cache before
reporting a container's memory:
- `pve-common` `src/PVE/CGroup.pm` `get_memory_stat`: `$res->{mem} =
$mem - $stat->{file};` on cgroup v2 (`memory.current`), and `$res->{mem}
= $mem - $stat->{total_cache};` on v1 (`memory.usage_in_bytes`).
- `pve-container` `src/PVE/LXC.pm` `vmstatus` stores that value with
`$d->{mem} = int($mem->{mem});`. `PVE::LXC::CGroup` inherits
`get_memory_stat` from `PVE::CGroup` without overriding it.
- `pve-manager` `pvestatd` `update_lxc_status` writes `$d->{mem}` into
RRD field 8. `/cluster/resources` (`PVE/API2/Cluster.pm` →
`PVE::API2Tools::extract_vm_stats`) returns `$entry->{mem} = ($d->[8] ||
0) + 0;`.

A QEMU guest's listing `mem` is the host's view of guest RAM, which does
include the guest's cache, so it stays pressure-unknown.

**Change**
- `unifiedresources.QualifyGuestMemoryForKind` now takes the guest kind:
other platform, Proxmox VM or Proxmox container.
- A current, dated `cluster-resources` reading counts as known pressure
for a Proxmox container and stays cache-inclusive and unknown for QEMU.
- `status-mem`, `status-freemem` and `derived-total-minus-used` are
unchanged for every guest type.
- `GuestMemoryEvidenceForResource` takes the kind from the resource
type, so the Patrol inventory, the observer runtime and AI query
projections agree.
- `QualifyGuestMemory(bool)` keeps the conservative QEMU reading for
callers that don't know the guest type.
- The wrong comments in `calculateLXCMemory` and the LXC monitor tests
are corrected.
- Everything else in a5baa7563b still applies: retained, undated,
unknown and unavailable readings still cannot establish pressure or
recovery.

**Tests**
- `TestPatrolAgentlessLXCListingMemoryIsPressure` (new) builds an LXC
and a QEMU guest at 97%, both on `cluster-resources`, through legacy and
canonical read state. The LXC gets a memory triage flag and alert review
reads its value; the QEMU guest gets neither.
- `TestGuestMemoryClusterResourcesIsTypeAware` (new) covers both guest
kinds, retained readings, the other cache-inclusive sources and the
resource-type mapping.
- The `cluster-cache` fixture in `TestPatrolGuestMemoryEvidence` now
expects pressure for the container variant. It previously encoded the
wrong behaviour.
- Against origin/main's production files (`go test -overlay`), the new
and updated Patrol tests fail; with this change they pass.

Refs #2762



Supersedes #3011, which failed the documentation recipe test that pinned
the old `QualifyGuestMemory(` call in Patrol; this commit also updates
that pin to `QualifyGuestMemoryForKind(`.
2026-10-17 03:21:14 +01:00
rcourtman 6cd7e1c7c1 Read agentless LXC listing memory as real pressure in Patrol
Patrol treated every guest's cluster-resources memory as cache-inclusive,
so an LXC without a linked Pulse agent, which only ever gets that source,
lost memory pressure entirely: no triage flag, forecast or anomaly at 97%
of its limit, a "may include reclaimable cache" caveat in the seed, and
older memory alerts sent to model review every run with any resolve
verdict discarded.

The premise holds for QEMU but not for LXC. Proxmox's container mem is
cgroup usage with page cache already subtracted: PVE::CGroup's
get_memory_stat returns memory.current minus memory.stat file (cgroup v2)
or usage_in_bytes minus total_cache (v1), PVE::LXC::vmstatus reports it
as mem, and pvestatd feeds that value to the RRD that /cluster/resources
reads. A QEMU guest's listing mem is the host's view of guest RAM and
does count the guest's cache.

Qualification now takes the guest kind. A current, dated cluster-resources
reading establishes pressure for a Proxmox container and stays unknown for
QEMU; status-mem, status-freemem and derived-total-minus-used stay
cache-inclusive for both, and retained readings still cannot prove
pressure. The typed read state derives the kind from the resource type,
so Patrol, the observer and AI queries agree. The calculateLXCMemory
comment that called the listing value cache-inclusive is corrected.

Contract-Neutral: monitoring change is a corrected comment in calculateLXCMemory and its tests; LXC memory collection and sources are unchanged
2026-10-17 00:38:36 +01:00
rcourtman 6dc43d298c Stage server update archives on the install filesystem, not /tmp
The server installer downloaded the release archive and extracted it
under /tmp. Debian 13 and many LXC templates mount /tmp as tmpfs, whose
pages are charged to the container's memory cgroup. A v6.5.0 archive is
~280 MB and extracts to ~750 MB, so an unattended update on a 1 GiB LXC
filled the cgroup with ~820 MB of shmem; the kernel OOM-killed the
container's systemd and Proxmox stopped the container mid-update.

Download and extract into owner-only hidden directories under the
install directory instead. It is always writable from the hardened
pulse-update.service sandbox, it is where the staged binary already
lives, and the disk headroom preflight now measures the filesystem the
update actually stages on. The Go updater already prefers its data
directory over /tmp for the same reason.

Unlike /tmp, the install filesystem keeps an interrupted run's staging
across reboots. Staging setup now removes stale staging directories that
match only the exact owner-only names, never symlinks or files, and only
once their ctime is over six hours old: install.sh has no update lock,
so age is what proves no live run still owns them. Every recursive
pulse chown of the install directory now goes through one helper that
skips staging, so the payload root still reads is never handed to the
service account and the ~750 MB tree is not rewritten for nothing.

The "Failed to print table: Broken pipe" line in the report was
systemctl list-unit-files | grep -q in v6.5.0's service discovery; main
already reads that inventory in full, and it was not the failure.

Contract-Neutral: Defect fix inside the existing private server-installer inputs and update-space boundaries; staging moves from tmpfs-prone /tmp to the install filesystem with no public contract change
2026-10-16 23:49:36 +01:00
rcourtman 84226ad7bc Count successful history reads beyond seven days
Measure delivered extended history before changing free and paid features.
Count only successful responses containing an older metric point and retain
only bounded daily totals. Expose the rolling sum through schema v19 and
Preview with matching privacy disclosure and explicit report coverage.
2026-10-16 19:21:03 +01:00
pulse-triage[bot] c1b58f5d4c Find affected versions without replaying an update
Explain the existing server, agent report and target displays, mutable image references and interrupted-upgrade chronology. Link the guidance from troubleshooting and Getting Help; retain unknowns and avoid privileged/private diagnostic exports.

Contract-Neutral: Documentation and source-linked help checks only; no runtime, protocol or permissions change.
Change-source: pulse-maintainer
2026-10-14 22:47:14 +01:00
pulse-triage[bot] 1c9374fb0c Explain Unraid empty slots without hiding missing members
Distinguish configured placeholders from assigned failures, explain online parity counts, and preserve existing evidence without array changes or another retest.

Contract-Neutral: Documentation-only guidance for existing Unraid collection and alert semantics; no runtime, wire, access or trust contract changes.
Change-source: pulse-maintainer
2026-10-14 20:00:33 +01:00