Commit Graph

5596 Commits

Author SHA1 Message Date
pulse-triage[bot] ba8b9fcd32 Compose retained guest History correction with current main
Preserve the exact reviewed History candidate and its own-parent browser receipt. The updated main frontier changes setup help only; executor readiness and complete source qualification remain unfinished.

Change-source: pulse-maintainer
2026-10-04 04:54:36 +01:00
pulse-triage[bot] 28bb0fb51a Keep paused guest filesystem readings truthful in History
Separate current and explicitly retained disk evidence in the existing guest drawer. Show the fixed safe read reason beside History, preserve dated observations and access withdrawal, and clear retained provenance only with fresh source evidence. Record desktop and touch browser verification; native backup thaw and release delivery remain separate.

Change-source: pulse-maintainer
2026-10-04 04:29:15 +01:00
pulse-triage[bot] 22f1654142 Integrate reviewed truthful TrueNAS setup acceptance help
Retain both exact specialist commits and their rendered-help evidence. Existing documentation and verification only; no runtime, dependency or product-surface expansion. Full frontend suites/build remain unverified after two guest-readiness failures; rendered Chromium/WebKit and focused static evidence are proportionate to this diff.

Contract-Neutral: Existing help and verification only; no runtime contract changes.
Change-source: pulse-maintainer
2026-10-04 04:18:11 +01:00
pulse-triage[bot] 1c999113a1 Separate TrueNAS setup acceptance from connection probes
Remove the one-cycle data guarantee at the first setup steps, explain which ordinary reads a successful system-information probe has not exercised, and retain the published 6.4.1/6.4.5 probe-timestamp warning without applying it to repaired builds. Preserve read-only, credential-free polling checks and verify their shipped rendering and keyboard path.

Contract-Neutral: Existing help and its verification only; no runtime, API, polling, access, persistence or retention change.
Change-source: pulse-maintainer
2026-10-04 03:28:45 +01:00
pulse-triage[bot] e7c2b37cf6 Keep fully cached Patrol usage in budgets and cost projections
Follow up #2118/#2350: ordinary input can be zero while cache writes or reads remain billable. Preserve cache-only successful and partial results, record them in the usage ledger, and include them in the history median and triggered-spend rate. Keep genuinely empty/expired history excluded and retain the existing five-minute prices and budget semantics.

Change-source: pulse-maintainer
2026-10-04 03:25:57 +01:00
pulse-triage[bot] da49bcdf8c Integrate reviewed guest filesystem provenance and phone value visibility
Change-source: pulse-maintainer
2026-10-04 03:13:42 +01:00
pulse-triage[bot] e382a5cd45 Integrate reviewed Podman CPU and TrueNAS probe evidence repairs
Change-source: pulse-maintainer
2026-10-04 03:00:48 +01:00
pulse-triage[bot] 10f181b500 Keep guest filesystem provenance visible in every display mode
Show retained or unavailable read context beside filesystem values across bars, sparklines and history lenses, with the full safe reason available to assistive readers and the existing drawer. Announce retained chart values as last known, and let narrow chart plots yield width to the numeric value without growing dense rows. Include fixed-reason regressions, subsystem obligations and inspected final-content Chromium/WebKit proof.

Change-source: pulse-maintainer
2026-10-04 02:23:36 +01:00
pulse-triage[bot] 5311a7c6fe Integrate reviewed first-tap guest disclosure repair
Preserve the exact reviewed guest touch commits and own-parent browser receipts. Retained final-source proof covers the small native eligibility repair; native thaw, installed recovery and release delivery remain separate.

Change-source: pulse-maintainer
2026-10-04 01:53:58 +01:00
pulse-triage[bot] 116211d7f2 Compose retained guest touch repair for final source qualification
Preserve d856689f and 826eaf2a and their own-parent browser receipts on the supplied current base. Complete the unexecuted final-binding source checks and production embed build without changing the repair or dropping Recovery and release-governance maintenance.

Change-source: pulse-maintainer
2026-10-04 01:27:37 +01:00
pulse-triage[bot] c211bfe522 Make monitored-container update help truthful about recovery
Replace a claimed 15-minute backup and guaranteed rollback with the implemented five-minute cleanup, shared-data and best-effort limits. Put independent backups and deployment-manager recovery before the action, preserve current-state checks, and distinguish image-update suppression from command authority.

Contract-Neutral: Documentation and validation only; no container runtime, command authority or API changes.
Change-source: pulse-maintainer
2026-10-04 00:50:18 +01:00
pulse-triage[bot] d856689f5b Restore first-tap guest details on touch browsers
Reuse the shared non-activating native row marker without moving actions out of delegated event ordering. Preserve nested controls, keyboard disclosure, row identity and conditional action removal. Cover guest/full-drawer touch input and safe backup guidance with exact browser proof and source regressions.

Change-source: pulse-maintainer
2026-10-04 00:31:00 +01:00
pulse-triage[bot] 3c0fdcc742 Integrate reviewed Recovery safe-reporting navigation
Preserve exact Product Intelligence commits 48dc32d1a3 and 2a9e4183a6. Correct the existing Recovery link in both shipped mirrors and retain its renderer and desktop/phone keyboard-navigation controls. Reviewed source-3ytpvq_m and content-bound browser evidence remain adequate; no native recovery or released availability is claimed.

Contract-Neutral: Existing help-link repair and regression controls only; no runtime or API contract changes.
Change-source: pulse-maintainer
2026-10-04 00:30:56 +01:00
pulse-triage[bot] 888d918ba1 Integrate batch-start upstream frontier without dropping reviewed repairs
Merge exact upstream 99927467f5. Resolve only the agent-lifecycle contract append conflict by retaining both monitor recovery ownership and AI usage export clauses. Frontend auto-merges preserve reviewed final bytes; no runtime conflict correction or browser receipt rebinding.

Change-source: pulse-maintainer
2026-10-04 00:00:18 +01:00
pulse-triage[bot] 9677b5cd60 Separate TrueNAS probes from runtime poll and readiness evidence
A saved connection test reads system.info on a separate client. Keep both probe results out of runtime timestamps, failures, retry cadence and inventory readiness. Preserve stored-secret and tenant boundaries, and validate the existing API evidence through real local client/poller/handler controls. Update the matching API, monitoring, lifecycle and recovery contracts together. This repairs the diagnostic gap in #2382; its native polling/session cause remains unverified.

Change-source: pulse-maintainer
2026-10-03 23:58:11 +01:00
pulse-triage[bot] ab978b6cfc Keep Podman CPU interval evidence when one-shot percentages are zero
Retain a baseline on every response and fall back to interval counters for zero, absent or invalid compatibility percentages. Preserve positive native units and Docker calculations, rebaseline on restarts and reject out-of-order intervals. Add connected collector controls and the matching monitoring and agent contracts. Addresses the source gap reported in #2447; native payload and reporter acceptance remain unverified.

Change-source: pulse-maintainer
2026-10-03 23:57:05 +01:00
pulse-triage[bot] 48dc32d1a3 Fix Recovery safe-reporting navigation
Resolve the shipped Recovery link to the actual Troubleshooting heading and bind it to rendered Markdown. Exercise keyboard and reload fragment navigation in desktop Chromium and phone WebKit.

Contract-Neutral: Correct an existing help link and add regression controls; no API or subsystem contract changes.
Change-source: pulse-maintainer
2026-10-03 23:24:02 +01:00
pulse-triage[bot] ffac59b6dc Compose exact upstream storage and workload presentation
Preserve reviewed backup-reader and canonical deferred-read status guidance with upstream measured-width disk labels. Resolve only additive test assertions, keeping lifecycle refusal, PMG replacement, phone projection and word-wrapping controls. The combined disk model matches the previously diagnosed 9f50f630 content and requires fresh owning-lane browser proof.

Change-source: pulse-maintainer
2026-10-03 23:20:52 +01:00
pulse-triage[bot] 0c827e7dd7 Compose reviewed backup response validation
Preserve reviewed c54aa9e3 unchanged alongside canonical recovery help and storage presentation. Retain its exact-source proof; obtain owning-lane proof for the remaining combined upstream model.

Change-source: pulse-maintainer
2026-10-03 23:19:47 +01:00
rcourtman 06a68dbff3 Warn on inherited npm advisories when the lockfile is unchanged (#2442)
Since 3 October the required Frontend check has failed on every open
pull request, including Go-only ones, because of GHSA-vfj7-8cjw-p6xm
(`braces` <= 3.0.3, high, no patched release). `braces` reaches the
frontend graph only through dev-only `tailwindcss` 3 and `jscpd` 4. `npm
audit --omit=dev` is clean, so the shipped bundle is not affected.

A pull request that leaves `package.json` and `package-lock.json`
untouched has the same dependency graph as its base commit. It can
neither add a finding nor remove one, so failing it blocks every fix
without making anything safer.

## What changes

`scripts/npm-audit-retry.sh` now treats findings the same way it already
treated an unreachable advisory endpoint:

- **The change moves the dependency graph, or edits the runner**
(`NPM_AUDIT_REQUIRE_RESULT=true`): any finding at any severity fails, as
before. A missing answer also fails.
- **The graph is the base commit's** (`NPM_AUDIT_REQUIRE_RESULT=false`):
the run warns instead, still naming every finding. A missing answer also
only warns, as before.
- **Only an explicit `false` relaxes the verdict.** An empty or
unrecognised value stays strict. This also tightens the outage path,
which previously relaxed on any value other than `true`.

The scheduled `npm-audit` scan and the daily dependency advisory watch
keep the strict default. An inherited advisory therefore still fails
once a day until the graph is fixed; `test_dependency_advisory_watch.py`
now proves this. No severity threshold, allowlist or suppression is
added.

## Landing

This change edits the runner, so its own Frontend audit runs in strict
mode and fails on this same advisory. It cannot pass the required
checks, so it lands only by an explicit maintainer merge. That is
intentional: the policy is relaxed by a human decision, never by a
change passing its own check.

Removing `braces` for real means migrating to Tailwind 4 and jscpd
5.4.0; that is tracked separately. Dependency PRs (#2352, #2278) stay
blocked until that lands.

## Verification

- `scripts/tests/test-npm-audit-retry.sh`: 19 cases pass.
- `test_npm_audit_retry.py` and `test_dependency_advisory_watch.py`
pass.
- `TestFrontendDependencySecurityAuditsAreRequired` passes.
- `check_workflow_trust.py` passes.
- The real runner against main's lockfile exits 0 with the warning and
all 7 findings named when `NPM_AUDIT_REQUIRE_RESULT=false`, and exits 1
with `::error::` when it is `true`.
2026-10-03 22:41:14 +01:00
rcourtman 5ef76a0bbd Show the last backup in Proxmox coverage and keep its tables whole on phones (#2448)
Supersedes #2435, whose branch conflicted with the Tailwind 4 move
(#2443) in `proxmoxHostTableModel.test.ts`. Same change, rebuilt as one
commit on current main with a fresh browser pass and receipt.

- **Coverage:** the Restore column is now Last backup, meaning the
newest completed PBS snapshot or PVE backup file. Guest snapshots no
longer count, matching the posture engine.
- **Phones:** the node, backup server, coverage and By date tables keep
their values whole on phones.
- **By date Details:** shows the archive format (`vma.zst`, `tar.zst`)
with the full volid on hover and in search.

Verified on a private mock stack at 1440, 560, 440 and 390px, in light
and dark. On phones, only identity strings clip.

A second commit restores two `storage-recovery.md` notes from main,
covering History touch inspection and pool-to-disk ownership. The
original branch had dropped them with a stale copy of the file.
2026-10-03 22:33:52 +01:00
rcourtman eaa4b965da Account Anthropic prompt-cache usage instead of dropping it (#2431)
Fixes #2350 (from #2118).

The Anthropic client logged `cache_creation_input_tokens` and
`cache_read_input_tokens` and then returned only `input_tokens` and
`output_tokens`, so every cached Patrol run reached the usage ledger,
the cost preview, the budget check and the weekly digest with its cache
buckets missing. #2350 reproduced the loss on both the `Chat` and
`ChatStream` paths.

Both response paths now carry the two buckets as fields disjoint from
`InputTokens` (streaming assigns them from `message_start` and the final
cumulative `message_delta` rather than summing). The agentic loops,
Patrol responses and run records sum them beside the ordinary totals,
the usage ledger and its persisted copies keep them, and
`cost.EstimateUsageUSD` prices each bucket at Anthropic's published
cache rates (5-minute write 1.25x, read 0.1x of the input rate), falling
back to the input rate for providers without a known cache price. Spend
summaries, the digest spend, the cost projection medians and the usage
export expose the buckets and price them the same way. `InputTokens`
keeps its meaning everywhere, so the telemetry token buckets are
unchanged.

Proof: `anthropic_test.go` (both response paths keep the buckets; the
final delta does not double them), `pricing_anthropic_test.go`,
`store_test.go`, `patrol_digest_test.go`,
`patrol_cost_projection_test.go`, `cost_persistence_test.go`, and
`ai_handlers_more_test.go` for the export in both formats. This repairs
lost accounting data; it is not a measured provider bill or a claim of
savings across six-hourly runs.
2026-10-03 22:30:26 +01:00
rcourtman a53f43b2b5 Proxmox and Docker page passes: storage words, first paint, table fits (#2449)
Supersedes #2432, whose branch conflicted with the Tailwind 4 move
(#2443) in `StackedDiskBar.tsx` and `DockerTasksTable.tsx`. Same eight
fixes, rebuilt as one commit on current main. The conflict resolution
keeps both this change and main's class renames (`rounded-sm` to
`rounded-xs`). A fresh browser pass and receipt are included.

Proxmox
- PBS datastores read Online in the storage vocabulary instead of
Unknown.
- The mock estate carries shared PBS storage as one cluster row.
- Storage types read LVM-Thin and NFS, and cluster-merged storage reads
"Shared · N nodes".
- REST-mapped resources carry PMG metadata, so the Mail Gateway table no
longer paints dashes on fresh loads.
- In Bars mode, multi-disk hosts show their fullest disk's percentage.
- REST rows carry source status, action readiness and technology.

Docker
- The containers table fits at laptop and phone widths.
- Swarm states read as words, and task times show as ages.
- Demo container names are unique per host.

Verified on a private mock stack built from this tree at 1440, 1280 and
390px, in light and dark.
2026-10-03 22:23:22 +01:00
rcourtman bab3530214 Carry Kubernetes job times into the controller row expansion (#2434)
## Why

The Workload Controllers table hides its Detail column below a 76rem
container, and that column was the only place a Job's completion time
and a CronJob's last success or last run were shown. The row expansion
rendered only the generic Observed state, Last seen, Identity and
Aliases, so a phone or a half-width pane had no way to read when a job
finished. At 390px the 15 percent Kind track also clipped "DaemonSet",
"StatefulSet" and "CronJob", and the Target track clipped "1
completions".

## What

- The drawer's Kubernetes model builds a per-kind controller section
(Job, CronJob, DaemonSet, StatefulSet, ReplicaSet) that the
always-visible summary tables render in the same slot as the Docker
container section, so the facts are one tap away at every width and on
the Infrastructure drawer too. Job rows lead with Started, Completed and
Duration; CronJob rows with Schedule, Last run and Last success; each
timestamp is the absolute time with its age in parentheses and wraps in
a phone-width cell. Target, counts, the StatefulSet service name,
Namespace and Cluster follow.
- The phone projection keeps Controller, Kind, Ready and Issues and
demotes Target with `platform-table-phone-hidden`, widening Kind to 25
percent so every kind label fits whole.
- The Target count pluralizes through `getPlatformResourceCountNoun`, so
a single completion reads "1 completion" in the row as it does in the
expansion.

## Verification

Playwright clip sweep (scrollWidth over clientWidth on every th/td and
their children) at 1440, 1280, 900 and 390px against a private mock-mode
stack, with each CronJob, Job, DaemonSet and StatefulSet row expanded at
every width:

- 390px: the Kind track is 90px and no kind label or target value clips;
only the four long controller names truncate with an ellipsis. The
wrapped timestamp values in the expansion no longer clip (a single-line
value had needed 169px in a 142px cell).
- 1440px: no new clipped cell; the StatefulSet service name, which the
Detail column truncates, now reads whole in the expansion.
- No viewport scrolls horizontally.

Unit tests cover the controller section per kind and the table's phone
classes and expansion content.
`frontend-modern/browser-verification.json` carries the receipt.

Builds on #2411. Supersedes #2417, which conflicted with main on the
shared browser-verification receipt.
2026-10-03 22:22:16 +01:00
rcourtman 68df09104b Fit metric bar labels by measured glyph widths, not character count (#2438)
## What was wrong

The metric, stacked memory and stacked disk bars choose between `60%`
and `60% (265 GB/440 GB)` by estimating the label's width. The estimate
was 5.5px per character plus 8. At the label's 10px type a digit is
6.7px wide and a full stop 3px, so the estimate was off by -7px to +5px
on real labels.

In the Kubernetes clusters table at a 560px viewport the memory bar is
113px wide, the estimate came to 112.5px, the label needs 118px, and it
rendered with an ellipsis. A sweep of the platform tables found 24 such
bars on `main`, all stacked memory bars: 3 on Kubernetes clusters at
560px, 4 on Proxmox overview at 900px, 16 on Docker overview and 1 on
Kubernetes nodes at 1440px.

## The fix

`estimateTextWidth` sums per-glyph advances instead of multiplying a
character count.

- It reads the advances once per page from a hidden probe that carries
the label's type classes, so the estimate follows whichever system font
the browser renders. The advances measured for the macOS system font
stand in where there is no layout (unit tests).
- The value is measured semibold and the detail after it at normal
weight.
- Each model adds the padding its own label sits in (4px in the metric
and disk bars, 8px in the memory bar's chip) instead of sharing one
constant.

Two more gaps in the same decision are closed:

- The stacked memory and disk bars now count the anomaly marker that
shares the label's line.
- The inline per-disk slots are sized after the gap between them. A
two-disk Proxmox node at 900px clipped `backup 80%` by 2px.

A flat safety margin was not enough: the error depends on which glyphs
the label holds, so a margin that stops the clipping also hides labels
that fit. Measuring each label in the DOM would add a layout read per
bar on the Workloads hot path.

## Verification

Playwright sweep of every table on 32 platform routes at 1440, 900, 700,
560 and 390px (160 loads, 2,579 bars), on this branch and on `main`
against the same mock backend:

| | `main` | this branch |
| --- | --- | --- |
| Bars whose chosen label does not fit | 24 | 0 |
| Clipped inline disk labels | 3 | 0 |
| Bars showing the long label | 567 | 550 |

Of the 17 fewer long labels, 24 are the clipped ones, 14 Proxmox guest
disk bars at 900px gained the long form, and 7 memory bars dropped it: 5
that had 1.0px to 2.8px to spare and 2 that overflowed by under 0.5px.

With every glyph forced to Verdana (10% wider) no bar clips; with Arial
(7% narrower) no bar clips and 237 more show the long label. WebKit
matches Chromium.

The probe is the estimator's only layout read: 1.7ms on the 429-bar
Proxmox overview, about 110ns per estimate afterwards. Bar widths still
come from the resize observer alone.

## Not changed here

The storage usage bar on Proxmox > Storage still clips at 390px (72
rows) and by up to 2.3px at 700px (19 rows). It is a different component
that always renders the long label and does not use the estimator; #2418
reworks it.
2026-10-03 22:11:05 +01:00
pulse-triage[bot] c54aa9e3e7 Reject unreadable backup responses before publishing inventory
Validate backup envelopes, source collections and consumed row fields without coercing completion flags, dropping bad rows or treating missing data as empty. Preserve independent evidence and explicit nil PVE collections, keep format errors private and retry only the failed source. Include parser and mounted regressions, subsystem contracts and inspected Chromium/WebKit final-content proof.

Change-source: pulse-maintainer
2026-10-03 22:03:13 +01:00
pulse-triage[bot] 4b1849bc6e Integrate reviewed recovery help safety and API guidance
Change-source: pulse-maintainer
2026-10-03 21:57:14 +01:00
rcourtman 47e947c207 Restore two storage-recovery notes this rebuild dropped
The original PR 2435 branch carried a stale copy of storage-recovery.md and deleted main's History touch-inspection and pool-to-disk ownership notes, which are unrelated to this change. The squashed rebuild inherited the deletion; this puts both notes back so the change only adds its own coverage clause.
2026-10-03 21:49:45 +01:00
rcourtman 8c75d9b119 Merge remote-tracking branch 'origin/main' into fix/anthropic-cache-usage-accounting 2026-10-03 21:47:09 +01:00
rcourtman 7d6b80dd3c Carry main's Patrol header note in api-contracts before merging main
PR #2445 and this branch both appended a section to the end of api-contracts.md. Adding main's section here, ahead of this branch's, lets origin/main merge without a conflict the commit hooks cannot conclude; the merged file keeps both notes.
2026-10-03 21:47:06 +01:00
pulse-triage[bot] f5925942f4 Integrate reviewed source-local backup inventory reads
Preserve the exact Web implementation and test commits with their own-parent browser receipt. Independent PVE and PBS availability no longer fabricates empty inventories or hides readable evidence.

Change-source: pulse-maintainer
2026-10-03 21:46:33 +01:00
rcourtman b8a0f87e6b Proxmox and Docker passes: storage words, first paint, table fits
Rebuilds #2432 as one commit on current main. Its branch conflicted
with the Tailwind 4 move (#2443) in StackedDiskBar.tsx and
DockerTasksTable.tsx; the resolution keeps this change and main's class
renames (rounded-sm to rounded-xs). The eight original commits' reasons
follow.

Read PBS datastore status in the storage vocabulary:
The PBS poller reports a datastore as "available", or "unavailable"
when PBS returns an error for it. The datastore adapter mapped that
string through the generic status mapper, which only knows online,
offline and warning, so every healthy PBS datastore showed as
"Unknown" in the Storage tab and an unavailable one was not flagged.

PVE storage already maps the same vocabulary through its own storage
mapper. Share that mapping so a PBS datastore reads online or offline
like any other storage.

Carry shared PBS storage as one cluster row in the mock estate:
The mock emitted each cluster's two shared PBS storages once per node,
each with its own usage figure. The real poller folds a shared storage
into one cluster-scoped entry, which users asked for in issue 1049, so
the demo's Storage tab contradicted the shipped behaviour: ten rows of
"west-backup-primary" with different usage and growth on a five-node
estate, and a hundred on the public demo.

The fixture now carries the merged shape: one row per store with the
reporting nodes listed and a cluster-scoped id, offline only when no
cluster node is online.

Name Proxmox storage types and shared hosts as operators know them:
The Storage tab title-cased any storage type it did not map, so the
default local-lvm on every Proxmox install read "Lvmthin" and an NFS
share read "Nfs". Those types now carry the names the Proxmox UI uses:
LVM-Thin, LVM, NFS, SMB/CIFS, iSCSI, ZFS, BTRFS, GlusterFS and ESXi.

A storage the poller merged across the cluster showed the synthetic
node marker "cluster" as its host. It now reads "Shared", with the
reporting node count when the storage lists its nodes.

Carry PMG metadata on REST-mapped resources:
The Mail Gateway table reads resource.pmg. The REST-to-Resource mapper
set every other provider facet at the top level but kept pmg only under
platformData, so a row sourced from the REST snapshot rendered every
PMG column (version, nodes, mail in, spam, virus, quarantine, queue,
deferred) as a dash. The websocket snapshot carries pmg at the top
level, so the table filled in only when a websocket row happened to
replace the REST row; on a fresh load the two transports race, and
about half the loads stayed blank for good.

The mapper now carries pmg like the other facets, and a test pins it.

Label multi-disk hosts with their fullest disk in Bars mode:
A host with more than one agent-reported disk draws its Disk cell as
one micro-bar per disk and no figure, while a single-disk host shows a
percentage and Trends mode shows one for every host. Bars is the
default view, and most Proxmox nodes have at least local-zfs beside a
data pool, so the question "which node is running out of space?" had
no at-a-glance answer for the rows that matter most; the column's own
sort key was a number the cell never showed.

The cell now carries the fullest disk's usage beside the micro-bars.
Every bar keeps equal weight and no disk is named in the row; the
mount and the per-disk breakdown stay in the title and the tooltip.

Carry source status, action readiness and technology on REST rows:
The same race that blanked the Mail Gateway table applies to three
more fields the API returns: sourceStatus, actionReadiness and
technology. The REST mapper set sourceStatus only under platformData
and dropped the other two, while websocket rows carry all three at the
top level. Docker container lifecycle actions read sourceStatus and
actionReadiness to decide refusals, storage rows read sourceStatus for
freshness, and search suggestions and the assistant context read
technology, so whichever transport won a fresh load decided whether
those consumers saw the data.

The mapper now carries all three, the REST type declares the two it
omitted, and the PMG mapping test pins them.

Fit the Docker containers table and read Swarm state as words:
On a 1280-1536px laptop window the containers table clipped its short
values: the engine read "docker 2…", host names lost their tail, and
the Update control itself was cut off, while the percentage-only CPU
and memory bars had room to spare. The compact widths now give those
columns their share. On a phone the row dropped to "runni…" with an
unreadable Restarts header beside a wrapped Update button; the phone
row now keeps container, state, CPU, memory and Update, and the
restart count stays in the row expansion until mobile width. The
images table on a phone showed "Not c…" for the update verdict and a
clipped host; it keeps image, size and update check there and defers
host and consumers to the expansion.

Swarm services showed the rollout state as the raw token
"rollback_started" and Swarm tasks showed a raw RFC3339 stamp with
microseconds as their start time. The state reads as words and the
start as an age, with the raw values in the title.

Keep demo Docker container names unique per host:
The demo scenario reused its curated container profiles for a second
round on hosts with more containers than profiles, so a host showed
two running "customer-portal" rows and every image's "used by" list
read "customer-portal, customer-portal". Docker refuses two containers
with one name on a host, so the duplicates read as a bug to anyone
evaluating the demo. A reused profile now takes a numbered suffix.

Contract-Neutral: Storage type labels, shared-host label, REST mapper carrying fields websocket rows already carry, Bars-mode disk label and Docker column fits are presentation and mapping only; owning unified-resources and storage-recovery clauses updated; no frontend-primitives primitive, API or runtime boundary change
2026-10-03 21:35:27 +01:00
rcourtman ae0158ba60 Show the last backup in Proxmox coverage; keep tables whole on phones
Rebuilds #2435 as one commit on current main. Its branch conflicted with
the Tailwind 4 move (#2443) in a host-table test; the three original
commits' reasons follow.

Name the last backup in Proxmox coverage, not the newest snapshot:
The Coverage table's Restore column showed the newest of every artifact,
including guest snapshots. A VM with a snapshot from last night and a
PBS backup from three weeks ago read "Restore 18h ago" in the healthy
green beside a "Needs attention" posture, and the only way to see why
was the row's hover text. Guest snapshots share the guest's storage;
the posture engine already refuses to count them ("snapshots alone do
not prove independent recovery"), so the row contradicted the server.

The column is now Last backup: the newest completed PBS snapshot or PVE
backup file. Snapshot-only rows show None and carry the engine's own
reason on hover, the guest snapshot keeps its dedicated column, and the
sort and the backup-location filter follow the same rule. The location
filter also stops treating running or failed artifacts as a latest
pointer, which the unfiltered model already did.

Keep Proxmox backup and node tables whole on phones:
On a 390px phone the Proxmox tables clipped the values users came for.
The nodes table showed six "Anal…" rows for the Analytics A–F cluster:
a sixth column (temperature) left the node name four characters wide
with the toggle and status dot in front of it. The backup server row
showed "H…" for Healthy, and the coverage and By date rows clipped
"18h ago" to "18 …" and "Running" to "Runni…".

Nodes now carry the same five columns as the guest table beneath them
with a wider identity cell; temperature returns from 440px, where it
fits. Backup ages use a suffix-free compact form ("18h") with the full
timestamp on hover. The server row keeps its status word and used
percentage whole and lets the backup count return at the next width,
and its stale header width classes no longer fight the colgroup. The
By date row keeps its source and state badges whole while the
repository moves to the row's hover title. Just above the phone
projection the servers' used/total pair and the coverage posture word
now fit, and at desktop width "Automation Lab Standalone" no longer
truncates in the nodes table.

Measured with a scrollWidth-over-clientWidth sweep of every table cell
at 1440px, 560px and 390px; only identity strings still clip, each with
its full text on hover.

Name the archive format in By date and widen phone guest names:
The By date table's Details cell showed a PVE backup's full volid,
"backup-vault:backup/vzdump-qemu-1002-2026_10_02-20_10_14.vma.zst",
which repeats the storage, guest type, VMID, and timestamp the row
already shows in their own columns and clipped in every one of its
rows on a 1440px screen. The one fact it adds is the archive format,
so the cell now reads "vma.zst" or "tar.zst", the volid stays on
hover and in search, and a provider with no format falls back to the
file name. The coverage disclosure's evidence table follows suit.

The shared guest table's phone name cell carries the expansion
toggle, status dot, and backup badge before the name, so the shared
30% identity anchor left a 390px phone 66px for the name and clipped
"artifact-cache-310" to "artifact-ca…". It now takes the same 38%
anchor the Proxmox host table uses, which gives the name 95px while
the four metric chips beside it still fit.

Measured with a scrollWidth-over-clientWidth sweep at 1440px, 560px
and 390px: the By date table has no clipped cell at desktop width, and
on phones only long identity strings still clip.

Contract-Neutral: Proxmox coverage, phone and mid-width column projections, By date Details and guest-table phone identity width are presentation only; owning unified-resources and storage-recovery notes updated; no workloads hot-path or frontend-primitives change
2026-10-03 21:25:59 +01:00
pulse-triage[bot] 3a8e84e626 Integrate reviewed backup observations and billing-safe demo profiles
Preserve exact Core candidate 1070ca275b, reviewed current main and batch-start upstream. Retained exact-source proofs cover the diagnostic fixture repair, unchanged guest writer, canonical encrypted billing and final composed build. Native PVE/QGA thaw and operational demo acceptance remain unfinished. Contract-Neutral: exact-history integration without new runtime or contract changes. Change-source: pulse-maintainer

Change-source: pulse-maintainer
2026-10-03 21:25:31 +01:00
pulse-triage[bot] 311d4a7cc9 Integrate batch-start upstream Patrol header repair
Preserve exact upstream bb4a137258 and its own-parent browser receipt while retaining pending reviewed main work. Contract-Neutral: exact-history upstream integration only; no additional runtime changes. Change-source: pulse-maintainer

Change-source: pulse-maintainer
2026-10-03 21:25:22 +01:00
pulse-triage[bot] d9292ef38c Keep backup inventory failures source-local
Distinguish PVE and PBS loading, failed and fulfilled inventories. Keep independent evidence usable, provide isolated retry, and withdraw prior inventory on organisation changes without new polling or caching. Preserve server health and canonical protection posture while marking incomplete counts. Cover lifecycle and recovery with mounted regressions, production-component browser proof and subsystem contracts.

Change-source: pulse-maintainer
2026-10-03 21:22:30 +01:00
pulse-triage[bot] 2201fd59b4 Make recovery help distinguish backup evidence from safe restore
The existing guide points to a retired page and documents ignored time and subject filters. Explain current platform views, provider verification limits, independent thaw and isolated restore acceptance; mirror the guide and bind examples to the read-only handlers.

Contract-Neutral: Recovery runtime, APIs, trust policy, frontend behaviour and dependency graph are unchanged; this corrects existing help and its regression checks.
Change-source: pulse-maintainer
2026-10-03 21:21:04 +01:00
rcourtman 2c1b3fd27e Merge remote-tracking branch 'origin/main' into fix/metric-bar-label-width 2026-10-03 21:10:23 +01:00
rcourtman ebda81d2be Merge remote-tracking branch 'origin/main' into fix/kubernetes-controller-expansion 2026-10-03 21:10:23 +01:00
rcourtman a37d7f7ed1 Merge remote-tracking branch 'origin/main' into fix/anthropic-cache-usage-accounting 2026-10-03 21:05:53 +01:00
pulse-triage[bot] 1070ca275b Preserve returned backup presentation and exact browser proof
Compose the existing Web completion without reparenting its source or own-parent receipts. Keep the guest guard, completed-backup truth, upstream disk hover and Unknown dot, and test-only exact Deferred assertions. Return the combined source for independent review and protected publication.

Change-source: pulse-maintainer
2026-10-03 20:49:38 +01:00
pulse-triage[bot] b0a4e5caff Compose billing and diagnostic repairs with reviewed current source
Preserve the exact backup witness and both owning histories, including upstream opacity, trusted-peer help and portable demo fixtures. The existing full-state and guest-safety contracts remain intact.

Change-source: pulse-maintainer
2026-10-03 20:49:37 +01:00
pulse-triage[bot] 6140b24bc2 Integrate reviewed completed-backup evidence and alert qualification repair
Preserve exact Web candidate 5355a41c08 and existing main work. Retained source-nhvhkcfu and own-parent browser receipts cover the final runtime and test contents; running backup activity no longer replaces completed evidence, and held notification tests distinguish badge rows from read warnings.

Contract-Neutral: Integration of independently reviewed source and proof; no additional runtime or contract changes.
Change-source: pulse-maintainer
2026-10-03 20:45:44 +01:00
pulse-triage[bot] 7d73969882 Keep demo runtime profile changes out of signed billing state
The helper could repersist legacy entitlement secrets and clear billing integrity while granting demo fixtures. Require the existing demo capability before mutation, leave all billing/key material untouched, and keep verification and encrypted legacy migration with the canonical application. Preserve full-state recovery, service ownership and the existing native route; seed only non-secret admitted fresh-runner fixtures. Add real canonical encrypted/legacy/HMAC connected controls and malformed or unprovisioned refusal-before-mutation coverage.

Change-source: pulse-maintainer
2026-10-03 20:25:40 +01:00
pulse-triage[bot] c381995d24 Keep proxy-auth help navigation independent of emoji fragments
The real Docs browser check reached the guide but could not resolve the guessed emoji heading fragment. Link the existing guide directly and verify its trust-boundary heading and text without inventing an anchor.

Contract-Neutral: Documentation and browser regression checks only; rendering, proxy trust and authentication runtime contracts are unchanged.
Change-source: pulse-maintainer
2026-10-03 19:47:00 +01:00
pulse-triage[bot] ee069f2144 Add independent bounded guest-write evidence for backup thaw
An OK PVE task and HTTP admission controls cannot establish thaw. Supply a credential-free guest-local fsync/readback witness and bounded offline record checks for the real #2439 job, without QGA probes, recovery actions or a replacement native platform. Require actual overlap, every covered filesystem and truthful monitoring resumption; retain native provenance and execution with Delivery.

Contract-Neutral: Measurement support for the existing guest-agent backup safety obligation only; production APIs, polling, access boundaries and release gates are unchanged.
Change-source: pulse-maintainer
2026-10-03 19:44:31 +01:00
pulse-triage[bot] bbf839a261 Keep completed guest backup evidence visible during activity
The real guest drawer replaced missing or old completed protection with a green running state. Preserve the completed age and tone, and show current activity separately as not completed yet. Ending activity without a new timestamp must not imply protection. Mounted and full-drawer VM/CT browser regressions preserve that distinction and the independent disk-lock guidance.

Change-source: pulse-maintainer
2026-10-03 19:36:44 +01:00
rcourtman 1bcc94df36 Keep the Patrol decision header pinned while a long decision scrolls
The attention detail header carries Back, Previous and Next issue on
phones and was authored sticky, but the inbox section's overflow-hidden
made that section the sticky scroll container. Below lg the header moved
exactly with the section, so on long decisions the queue controls scrolled
away. overflow-clip keeps the rounded-corner clipping without creating a
scroll container, so the header now pins against the app scroll shell.

The header also gets the opaque bg-surface/95 it was first authored with.
PR 2443 dropped it because Tailwind 3 never rendered it; now that the
header actually sticks, content would otherwise show through it.
2026-10-03 19:36:24 +01:00
pulse-triage[bot] cbbed83add Make reverse-proxy help match the forwarded-header trust boundary
Explain immediate-peer trust before proxy setup, constrain copyable HTTPS examples and preserve authentication during diagnostics. Keep both shipped guides in sync and cover the missing guidance in the documentation regression checks.

Contract-Neutral: Documentation and regression checks only; proxy trust, authentication, routing and runtime behaviour are unchanged.
Change-source: pulse-maintainer
2026-10-03 19:28:18 +01:00
pulse-triage[bot] 42f43f0a3e Merge reviewed truthful configuration migration help
Preserve exact candidate 76484e4e8c alongside newer canonical Web/Core work. Retained matching-graph source and desktop/phone browser proof cover the unchanged final migration content.

Contract-Neutral: Existing migration guidance, warning copy and regression proofs only; no archive, recovery or runtime contract change.
Change-source: pulse-maintainer
2026-10-03 18:39:04 +01:00