Commit Graph

4335 Commits

Author SHA1 Message Date
rcourtman a585eab712 Canonicalize mobile row disclosures 2026-08-24 11:09:53 +01:00
rcourtman e9fdd18570 Make large-estate navigation and updates incremental 2026-08-24 10:39:15 +01:00
rcourtman dec1c94c27 Define recovery list pagination bounds once in the recovery model
Follow-up to 6686cdce2: the 100-default/500-max list page bounds existed
as separate untyped constants in internal/api and internal/recovery/store,
relying on a contract clause to keep them aligned. Export
DefaultListPageLimit / MaxListPageLimit from internal/recovery/model
(re-exported through internal/recovery) and alias both consumers to them,
so drift is impossible by construction. store_test.go and
recovery_handlers_test.go pin both consumers to the shared constants;
the three pagination-meta contract clauses now name the single source.
2026-08-24 10:21:10 +01:00
rcourtman 9e37d629ac Measure node connection test outcomes
Telemetry could see only saved connections, so an install that tried to
reach a node and could not was indistinguishable from one that never
opened the add-node dialog. Both report zero configured connections and
stall at the same activation stage. Fleet data shows that population is
real and concentrated three to one in container deployments, and nothing
recorded whether those installs attempted a connection at all.

Record node connection test attempts and failures in a bounded,
day-bucketed tally in the config directory, pruned to a 31-day retention
window, and report both over the install-ID rotation window as
node_test_attempts_30d and node_test_failures_30d.

Recording starts only once a request carries a target and credentials, so
an incomplete form is never counted as a node that could not be reached.
A host string that turns out to be unusable does count, because the
attempt was made and it failed. Only the add-node dialog endpoint is
instrumented: instrumenting the unused test-config endpoint as well would
double-count a single operator action.

The tally holds counts alone. Hosts, credentials, and error text never
enter it, which is why it is plain JSON rather than encrypted history.
2026-08-24 10:17:17 +01:00
rcourtman 6417319b1e Accept build-output proof for vite.config.ts commits
The deployment-installability verification policy routed
frontend-modern/vite.config.ts through the dev-runtime orchestration
proof set, all of which exercise the unbuilt hot-dev runtime. No
accepted proof could observe production build output, which is why
c4af728c0 (preload posture change) needed
PULSE_ALLOW_CONTRACT_NEUTRAL_COMMIT.

Split vite.config.ts into its own frontend-build-output path policy:
the accepted set keeps every dev-runtime proof, so dev-server-facing
edits are unchanged, and adds
frontend-modern/scripts/check-bundle-size.mjs, which now also asserts
the built index.html posture the contract clause pins: modulepreload
links limited to the entry's static imports (no lazy route chunks) and
import map integrity coverage of every built JS asset. The guard test
pins the new policy's accepted set.

Verified against the built output: flipping preloadDynamicChunks to
true fails the check with 47 lazy-chunk preload violations; the
healthy build passes. Full canonical-governance chain run locally, all
exit 0.
2026-08-24 09:23:03 +01:00
rcourtman 6686cdce2c Report recovery pagination meta from the normalized limit
/api/recovery/points and /api/recovery/rollups clamp the requested page
size to [100 default, 500 max] in both the mock paginators and the store
paths, but the meta block was computed from the raw query value. A client
requesting limit=1000 with 1200 rollups was told totalPages=2 while the
server served 3 pages of 500, so iterating totalPages silently dropped
rollups; limit<=0 reported totalPages=1 at an effective limit of 100.

Normalize page and limit once at parse time, compute meta from the
normalized values, and echo the effective limit. Contract clause 34 in
api-contracts.md pins the obligation; storage-recovery and agent-lifecycle
record the boundary alignment and adjacency; recovery_handlers_test.go
pins above-max and non-positive limit meta.
2026-08-24 09:18:36 +01:00
rcourtman 29cbf73bba Register resource-payload static-metadata coverage gap
The browser performance audit measured the client-facing resource
stream as a primary scalability cost at estate scale: a 4.73MB
single-frame snapshot at 1,508 resources, ~3KB of mostly-static
metadata per resource (only 10 distinct capabilities blobs across the
whole estate, identity alias history, aiSafeSummary prose, and policy
routing shipped to every browser), and ~1s of blocked main thread per
delta on desktop hardware. Slimming the stream is a wire-format change
with consumers beyond frontend-modern (pulse-mobile OTA compatibility,
Pro surfaces, AI runtime), so it is registered as a triaged coverage
gap for an owned slice instead of an opportunistic patch. Evidence
record carries the measured payload composition.
2026-08-24 09:04:16 +01:00
rcourtman c4af728c0d Stop modulepreloading every lazy chunk at cold start
The SRI plugin's default preloadDynamicChunks injected modulepreload
links for all ~50 lazy chunks into the built index.html — 3.1MB raw
(4.2MB decoded): every Settings panel, Alerts, Chat, AI Intelligence,
all six platform pages, and both locale bundles fetched and compiled up
front, defeating route-level code splitting exactly where it matters
(slow devices, tab-evicted mobile browsers that cold start often).

Disable dynamic-chunk preloading; the entry keeps its three static
vendor preloads and dynamic-import integrity stays enforced through the
generated import map integrity block (112 entries verified in the built
output). Measured on a 4x-CPU-throttled mobile profile against the
50-node mock estate: cold-load long tasks 32s -> 18s, scripts fetched
99 -> 62, decoded JS 4.2MB -> 2.3MB.

Contract-Neutral: build-output preload posture change: deployment-installability's dev-runtime orchestration proof files all run the unbuilt hot-dev runtime and cannot observe built index.html preloads; verified instead by direct built-output inspection (0 route-chunk preloads, 112 importmap integrity entries) and 4x-throttle before/after measurement; substantive contract clause ships in this same commit
2026-08-24 09:02:21 +01:00
rcourtman 6d3ec88769 Stabilize nav tab identity across websocket ticks
The primaryTabs/utilityTabs memos in AppLayout rebuild their arrays from
live store reads; activeAlerts is replaced wholesale whenever a state
frame carries it, so every reference-keyed <For> consumer (desktop tab
strip and the mobile bottom bar) tore down and recreated all nav buttons
even when nothing visible changed. Probed on the 50-node mock estate:
3 of 4 mobile bottom-bar buttons and 4 of 10 desktop tabs were detached
within 40s of websocket frames; taps landing mid-rebuild die silently.

Reuse previous tab object references (and the previous array identity)
when a rebuilt list is structurally unchanged, so downstream <For>s keep
their DOM. With the fix the same 40s probe keeps every nav element
connected on both form factors. MobileNavBar's proof suite now pins the
DOM-identity behavior and App.architecture pins the stabilizer wiring;
contract notes recorded in frontend-primitives, cloud-paid, and
ai-runtime.
2026-08-24 08:58:49 +01:00
rcourtman 17bb2b3b7d Scale large-estate rendering and navigation 2026-08-24 00:31:39 +01:00
rcourtman 87ee3cd449 Fix command policy after agent reinstall
Project freshly minted installer command intent onto the stable host before returning remote config, and consume that intent once so later admin policy changes remain authoritative.
2026-08-23 23:39:20 +01:00
rcourtman fd7f4156ca Fix large-estate storage rendering performance 2026-08-23 22:20:03 +01:00
rcourtman 1d3ee7a1b3 Align Proxmox node search with visible guests 2026-08-23 21:59:22 +01:00
rcourtman 6794971199 Eliminate large-estate scroll blanks 2026-08-23 20:18:48 +01:00
rcourtman 10116cc17e Scale large-estate realtime monitoring 2026-08-23 19:58:40 +01:00
rcourtman 771d583f4a Sync Proxmox node table with workload search 2026-08-23 19:31:34 +01:00
rcourtman 35b8c0a4c2 Canonicalize Proxmox backup view routes 2026-08-23 18:12:22 +01:00
rcourtman ae9cfb1da8 Restore mobile Proxmox node visibility 2026-08-23 17:48:00 +01:00
rcourtman 4182f79028 Eliminate workload virtualization scroll gaps 2026-08-23 17:05:15 +01:00
rcourtman d8fe2a9358 Stabilize large-estate workload scrolling 2026-08-23 16:32:53 +01:00
rcourtman 4040a79f4f Fix workload virtualization scroll ownership 2026-08-23 15:51:40 +01:00
rcourtman 3bc613c915 Scale large-estate workload and Proxmox demo performance 2026-08-23 15:09:32 +01:00
rcourtman 6869612c66 Isolate PC compilation from SignPath workflow 2026-08-23 15:02:33 +01:00
rcourtman 32d7b22996 Use trusted PC for release compilation 2026-08-23 14:41:11 +01:00
rcourtman 567eca2572 Harden stable release convergence 2026-08-23 14:21:09 +01:00
rcourtman 2f3d224997 Use hosted container qualification for stable releases 2026-08-23 12:43:18 +01:00
rcourtman 0f369a4b0d Use hosted compilation for stable releases 2026-08-23 12:16:14 +01:00
rcourtman c1d0aaa0d5 Approve v6.3.1 unsigned Windows exception 2026-08-23 12:02:53 +01:00
rcourtman 34ae5c98f9 Fix SignPath release provenance 2026-08-23 11:39:21 +01:00
rcourtman e51618a9ce Prepare v6.3.1 stable patch release 2026-08-23 10:38:19 +01:00
rcourtman ddf081a55a Bound Docker storage inventory collection 2026-08-23 09:34:40 +01:00
rcourtman 66eb537522 Fix local subscription CLI service setup 2026-08-23 09:28:44 +01:00
rcourtman 3a9dffa850 Fix Docker command recovery after token rotation 2026-08-23 09:18:44 +01:00
rcourtman bce5564025 fix notification terminal failure recovery 2026-08-23 09:05:54 +01:00
rcourtman 434e1448ff Restore Docker update preflight through unified agent 2026-08-23 08:35:26 +01:00
rcourtman ea5c105ff2 Log refused actions and name the missed command-agent lookup
A refused action plan, decision, or execution returned its 409 to the
client and left no trace in the server journal, so every remote report
of "Docker / Podman command agent is not connected" stalled on greps
that could never match anything. Refusals now log one warn line with
the resource, capability, and reason code, and the Docker command-agent
resolver reports which lookup missed (stale enrollment token binding vs
agent-id/hostname session), carried as an optional diagnostic detail on
the readiness contract and in the refusal envelope.

Refs #1728
2026-08-23 06:33:30 +01:00
rcourtman 73c4147d5e Restore owner risk acceptance wording (#1760)
Co-authored-by: rcourtman <rcourtman@users.noreply.github.com>
2026-08-22 14:05:29 +01:00
rcourtman 124a2806ca Record v6.3.0 publication proof 2026-08-22 12:20:22 +01:00
rcourtman ca311323e9 Join every release compilation task 2026-08-22 11:07:26 +01:00
rcourtman b88e05d1ce Prepare v6.3.0 stable release 2026-08-22 10:35:27 +01:00
rcourtman a0770b87bb Ground backend shard admission in measured worker headroom
The three-shard backend gate landed with a 16 GiB admission requirement
that exceeded the 8-vCPU PVE worker's own idle availability (measured
16.1-16.7 GiB, and 14.1-14.9 GiB beside the sibling release compilers),
so the next release would have hard-failed at admission before running a
single test. Direct probes on the worker measured the complete gate at a
~6-7.5 GiB footprint (8.9 GiB MemAvailable floor from a 16.4 GiB start,
zero swap), so admission now requires 10 GiB for three shards and 8 GiB
for two, and degrades the shard count instead of failing the release
when the bounded wait expires without headroom.

Shard CPU is now weighted by planned test volume from the plan manifest.
Top-level tests execute serially per test-binary process, so width mainly
buys runtime, GC, and race-detector headroom for the 3595-test prefix
shard; the ~15-test wait-bound tails cannot use it. Probes measured the
prefix shard at 569s with 2 procs versus 484s with 4, with total
allocation still equal to the worker's vCPU count.

Validated by three direct runs of the canonical script on the worker:
the full gate passed in 8m10s wall (auto-admitted three shards, procs
4/2/2, shard walls 484s/331s/224s) against the 12m09s two-shard release
job measured in run 32514803052. One rig run also proved the gate fails
closed: a stale contract pin failed the non-API graph and the harness
terminated every descendant shard process.
2026-08-21 22:16:33 +01:00
rcourtman f38e95eb72 feat(telemetry): export the Patrol blocked cause at schema v10
An enabled Patrol that can never run and one that runs and finds nothing
were indistinguishable in the fleet: both presented as high run counts
with zero AI calls and zero findings. The install that motivated this
sat blocked for over a month because provider initialisation failed once
at boot and was never retried; the self-heal landed separately, but
telemetry still cannot see which blocked cause dominates in the field.

Schema v10 exports the fixed machine cause code (for example
provider_not_configured) only while Patrol is in the blocked runtime
state. The cause rides the router-owned Pulse Intelligence snapshot into
the outbound ping. Blocked-reason text, provider endpoints, model names,
and configuration stay on the install; an untyped blocked reason exports
nothing rather than free text, and a disabled, active, or mid-run Patrol
exports an empty value even when a stale cause is still recorded.
2026-08-21 21:43:54 +01:00
rcourtman 7c37a85cb2 Surface and self-heal Patrol's provider-unavailable state
Field telemetry showed installs with Patrol enabled recording weeks of
empty error runs (runs_30d=122, ai_calls=0, findings=0): provider
initialization failed once at boot (model resolution can need the
provider's live catalog, so Pulse racing a booting Ollama server loses)
and was never retried, while the run loop kept recording "Patrol
provider not configured" errors that told operators who had configured
a provider to configure one.

- Retry provider initialization on every scheduled run, so a boot-time
  race strands Patrol for at most one interval instead of until the
  next settings save. LoadConfig records the redacted init failure.
- Name the real failure in the blocked reason and run record when the
  configured provider failed to initialize, instead of claiming no
  provider is configured.
- Raise the deduped Patrol runtime finding when scheduled runs are
  skipped by a persistent readiness blocker or missing provider, so the
  state reaches the findings surfaces and alert notification channels
  once, instead of living only on the Patrol page banner. Transient
  circuit-breaker blocks stay finding-free; the attempts that opened
  the breaker already raised their own.
- Resolve the runtime finding when Patrol is turned off; opting out is
  a resolution, not a state to keep nagging about.
- Record the extended runtime-failure surface in the ai-runtime
  subsystem contract.
2026-08-21 21:05:54 +01:00
rcourtman 9ef94418e8 Accelerate release convergence on PVE 2026-08-21 20:41:04 +01:00
rcourtman 779f9a10bc Follow extracted resource service in frontend guard 2026-08-21 19:38:28 +01:00
rcourtman 5c26022d65 Join frontend before embedded server builds 2026-08-21 19:16:47 +01:00
rcourtman 89eba99bb4 Build frontend for Pro packaging profile 2026-08-21 19:04:23 +01:00
rcourtman 0cd70edd90 Prepare v6.3.0-rc.6 release 2026-08-21 18:56:45 +01:00
rcourtman fa156e0bb1 Record chart and resource qualification 2026-08-21 18:53:27 +01:00
rcourtman 08827bb887 Extract chart and resource query services 2026-08-21 18:36:21 +01:00