Commit Graph

5621 Commits

Author SHA1 Message Date
pulse-triage[bot] 768952fd68 Integrate reviewed used-memory history retention
Accept exact Core candidate 0ea87307e2. Retained source-0qcd2wj7 proves parent omissions, final retention and connected readers under race, vet and affected-package build; intervening canonical changes do not touch the affected Go source.

Change-source: pulse-maintainer
2026-10-04 06:53:37 +01:00
pulse-triage[bot] 0e41d8d213 Integrate reviewed workload guest-read evidence
Change-source: pulse-maintainer
2026-10-04 06:46:21 +01:00
pulse-triage[bot] 630f45a265 Integrate reviewed least-privilege token guidance
Change-source: pulse-maintainer
2026-10-04 06:46:12 +01:00
pulse-triage[bot] 0ea87307e2 Keep used-memory history within its retention window
Periodic guest and node cleanup omitted raw memory-used samples from both expiry and live-entry checks. Trim them with the existing retention and backing-array policy without deleting a still-live byte series. Cover every supported History series, byte-array reclamation, concurrent cleanup and poll-to-chart/metric-window resumption. No SQL retention, source-selection or wire changes.

Change-source: pulse-maintainer
2026-10-04 06:33:37 +01:00
pulse-triage[bot] 2323550225 Preserve native guest read evidence through workload projection
Forward existing disk deferrals, guest-agent state and VM locks through API and canonical snapshots. Supersede omitted optional fields only on an explicit native VM outcome, consistently across full and fast merges. Withdraw unavailable row numerics while preserving valid prior and measured-zero readings. Add connected hook, merge, mounted and inspected browser controls without issuing guest or backup commands.

Change-source: pulse-maintainer
2026-10-04 06:30:19 +01:00
pulse-triage[bot] de08129671 Integrate reviewed complete-response guest lock checks
Accept the exact Core candidate and its retained parent/final race evidence. Reject incomplete authoritative VM configuration bodies before guest-agent dispatch and fresh telemetry publication; preserve existing canonical frontend and documentation work. Native PVE/HAOS-QGA thaw acceptance and containing-release follow-through remain separate.

Change-source: pulse-maintainer
2026-10-04 06:21:55 +01:00
pulse-triage[bot] 74c3522700 Align API-token help with least-privilege presets
Correct the existing configuration help against the live preset model and token client: reporting does not include lifecycle authority, exposed credentials need prompt revocation, and kiosk display preferences do not restrict credentials or guarantee persistence. Keep the shipped mirror and add runtime-model-bound documentation controls and browser help validation.

Contract-Neutral: Documentation and test fixtures only; no runtime token, authorization, navigation or delivery contract changes.
Change-source: pulse-maintainer
2026-10-04 06:11:53 +01:00
pulse-triage[bot] 53cfdf6020 Integrate reviewed truthful guest filesystem displays
Preserve exact reviewed History and incomplete-reading commits with their own-parent browser receipts. Retained final compiler, 407 regressions and production-build proof cover runtime content; preserve current data-retaining removal guidance.

Change-source: pulse-maintainer
2026-10-04 06:02:52 +01:00
pulse-triage[bot] 0f3575bdcf Integrate reviewed data-preserving server removal guidance
Change-source: pulse-maintainer
2026-10-04 05:55:34 +01:00
pulse-triage[bot] f7eeabc400 Compose the complete-response guest lock repair with current main
Preserve current safety evidence, installer guidance and reviewed release-browser source while validating the previously unexecuted runtime response-boundary correction. No native thaw or old executor cleanup is inferred.

Change-source: pulse-maintainer
2026-10-04 05:51:41 +01:00
pulse-triage[bot] 5d1b03c1b9 Compose retained filesystem safety repairs for final qualification
Preserve the exact History and incomplete-reading candidates and their own-parent browser receipts while including the current assigned main. No frontend resolution or receipt rebinding.

Change-source: pulse-maintainer
2026-10-04 05:50:50 +01:00
pulse-triage[bot] fa6282b716 Preserve persistent state in server removal guidance
Replace destructive default uninstall recipes with bounded service/container removal and explicit erasure warnings. Explain default Helm PVC ownership, temporary storage and updater/agent lifecycle boundaries; retain matching data and encryption keys.

Contract-Neutral: Existing documentation and focused verification only; no installer, runtime, API, storage, privilege or lifecycle contract delta.
Change-source: pulse-maintainer
2026-10-04 05:26:00 +01:00
pulse-triage[bot] acace4d4f2 Integrate reviewed backup resumption evidence correction
Retain exact Core candidate. Nineteen focused committed-source checker and CLI methods establish rejection of unsupported post-task resumption while preserving calibrated healthy records. No production polling or native thaw acceptance is changed.

Change-source: pulse-maintainer
2026-10-04 05:20:55 +01:00
pulse-triage[bot] b42563d966 Integrate reviewed narrow-identity release browser route
Retain exact Delivery candidate and its reviewed history. Offline packet, lifecycle and Tailnet controls pass; unchanged Chromium refusal receipts remain bound to their executed source. Native collection still requires protected publication, host activation and credential-administrator confirmation of dedicated tag:ci-deploy scope and self-only access.

Change-source: pulse-maintainer
2026-10-04 05:20:54 +01:00
pulse-triage[bot] 81b07e8a90 Keep incomplete filesystem readings unavailable
Require finite capacity and measured used bytes in the existing filesystem list and guest Overview. Missing, invalid and sentinel readings remain unavailable rather than a healthy empty disk; measured zero and valid byte-derived readings stay visible. Preserve the exact retained History correction and add mounted, multi-filesystem and browser controls.

Change-source: pulse-maintainer
2026-10-04 05:15:29 +01:00
pulse-triage[bot] 1920db3c34 Require observed post-task reads in backup resumption records
Reject a resumed disk or memory History claim when the complete native trace lacks the corresponding successful new guest read after backup completion. Preserve calibrated clock bounds, normal later polls, independent filesystem writes and native provenance review; no QGA command or runtime behaviour changes.

Contract-Neutral: Tighten consistency checks for the existing backup-safety measurement only; production polling, interfaces, access boundaries and release gates are unchanged.
Change-source: pulse-maintainer
2026-10-04 05:09:18 +01:00
pulse-triage[bot] 2fb4bf9eee Bind release browser qualification to the narrow CI identity
Use a dedicated Auth Keys write client restricted to tag:ci-deploy, never the broader demo registration. Reject missing configuration and validate the actual running Self tag and DNS before Serve. Keep exact-source, denial-stop, no-replay and cleanup contracts, with connected offline registration and Serve controls.

Change-source: pulse-maintainer
2026-10-04 04:57:17 +01:00
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] a847b05e3e Compose returned release browser safety candidate with current source
Preserve the reviewed denial and recovery corrections for an additive least-privilege registration repair. No native acceptance is inferred.

Change-source: pulse-maintainer
2026-10-04 04:46:24 +01:00
pulse-triage[bot] 01adf338a4 Keep installation checks readable and require a loaded unit
Visual review found the bounded systemctl example clipped its option lines on a phone. Give each property its own line and distinguish a missing unit from a loaded root service before interpreting its settings.

Contract-Neutral: Documentation and focused verification only; no installer, runtime, API, persistence or security contract delta.
Change-source: pulse-maintainer
2026-10-04 04:37:48 +01:00
pulse-triage[bot] a6959e571b Keep manual server installation help on the hardened path
Replace the root-only hand-written service example with the signed server install path and bounded effective-unit checks. Explain that existing custom units survive updates and cannot be migrated safely by changing User alone. Exercise the real rendered guide and retain state and credential safeguards.

Contract-Neutral: Existing installation help and documentation verification only; no installer, runtime, API, persistence or security contract changes.
Change-source: pulse-maintainer
2026-10-04 04:32:48 +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] 227f4f7ef9 Require complete VM config bodies for guest-agent lock checks
Do not admit guest commands or publish their payloads from an unlocked JSON prefix when the authoritative config response is incomplete. Preserve bounded ordinary config reads, live CPU and I/O observations, cache timestamps and healthy resumption.

Change-source: pulse-maintainer
2026-10-04 04:11:34 +01:00
pulse-triage[bot] 73b790b89b Stop release browser access at every authenticated refusal
Bind anonymous probes at request start, record bounded navigation/API/SSE denial, close the page immediately and suppress recovery authentication when the upgrade receipt is refused or unavailable. Exercise real Chromium response controls through the actual shell recovery guard.

Change-source: pulse-maintainer
2026-10-04 03:44:51 +01:00
pulse-triage[bot] f0ff193402 Compose returned browser release candidate for refusal repair
Change-source: pulse-maintainer
2026-10-04 03:35:01 +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] 619133aa54 fix(release): admit real archive sizes and enforce workflow trust
Live stable and RC archive metadata exceed 256 MiB; retain a streaming bounded 512 MiB archive/16 KiB signature/1 GiB binary contract instead. Disable automatic setup caches in the CI credential job and encode derived command outputs with the reviewed writer. Add regressions; do not relax workflow or release guards.

Change-source: pulse-maintainer
2026-10-04 03:00:30 +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] fdf464578a test(release): exercise exact published RC through Tailscale browser
Reuse the signed-install lifecycle assertions on a fresh public hosted VM without Docker identity overrides. Bind immutable release assets/control, observe one real UI apply/SSE/modal journey, retain sanitised terminal evidence and stop access refusals without reauthentication. Update the deployment contract and execute its recovery-access guard; release judgment and gates are unchanged.

Change-source: pulse-maintainer
2026-10-04 02:15:25 +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