Commit Graph

135 Commits

Author SHA1 Message Date
courtmanr@gmail.com 1dc19bfec0 Remove dead cache-aware RRD fields from the guest RRD path
Recorded PVE 8 and PVE 9 guest rrddata responses (fixtures under
pkg/proxmox/testdata/rrd/) prove guest RRD never carries the cache-aware
memused/memavailable columns — they exist only in node RRD — so every
consumer branch reading them was dead code that #1634's listing fallback
(7d7d2b6a3) had already routed around.

Drop the two fields from GuestRRDPoint (now time/maxmem only, matching
the recordings), delete the dead VM RRD memory fallback and its
getVMRRDMetrics/getVMRRDMemory helpers plus the vmRRDMemCache they fed,
remove the pointless per-poll guest RRD fetch from the LXC memory path,
and retire the guest RRD lookups from PVEClientInterface. VMMemoryRaw
loses its never-populated RRD diagnostic fields, and guest reliability
scoring no longer treats the node-only rrd-* sources as trusted guest
evidence. The knownDeadGuestRRDFields allowlist in the fixture
alignment test is gone; a new reflection guard in
code_standards_test.go keeps GuestRRDPoint pinned to recorded columns,
and cleanupRRDCache pruning of the guest-agent meminfo cache gains
direct coverage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 18:36:50 +01:00
courtmanr@gmail.com 13371a6b6c Surface host-agent identity collapse from cloned machine-ids
Host agents key their identity on the machine-derived agent ID, so MSP
template deployments that clone /etc/machine-id fold two physical
machines at different sites into one host row whose reports overwrite
each other (hostname, report IP, and interfaces flapping between
sites), silently poisoning node-agent linking.

Mirror the Docker host identity-collapse doctrine (#1584) for host
report ingest: track hostname and report-IP revisits per resolved
agent identity inside the monitoring-owned flap window, publish an
active conflict as models.Host.IdentityConflict through unified
resources, and warn on the Machines page. The report IP is tracked
alongside the hostname because template fleets often reuse hostnames
across sites (pve01 at two customers), leaving the address as the only
field that betrays the clone. A one-time hostname rename never
revisits and is not flagged; the conflict clears on its own once only
one machine keeps reporting for the window.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 12:26:18 +01:00
rcourtman 49217d284d fix: correct Proxmox guest rate sampling 2026-07-24 10:26:50 +01:00
rcourtman 8d23529c02 Fix availability check identity projection 2026-07-23 23:46:34 +01:00
rcourtman 9f9e02e811 Refuse dispatch when action readiness is lost 2026-07-20 21:44:59 +01:00
rcourtman b6a74576bc Integrate trust-gate reliability fixes 2026-07-20 16:03:29 +01:00
rcourtman 92c567e41d Make agent artifact guard quote agnostic
Contract-Neutral: The canonical agent artifact guard preserves the existing unified-agent contract while accepting equivalent JavaScript quote styles.
2026-07-20 09:14:40 +01:00
rcourtman 69533c7afb Build canonical availability resource facets 2026-07-19 15:11:01 +01:00
rcourtman 18cb497de1 test(unifiedresources): drop the retired run-command validator pin
The upstream removal of HandleRunCommand's dead legacy body (ec5e44da0)
deleted TestNormalizeRunCommandApprovalTarget with it, but the v6
host-alias standards test still required that test's snippet in
ai_handlers_test.go, so TestV6DirectHostAliasValidatorCoverage failed.
Drop only the retired validator's snippet; the surviving execute and
investigate-alert validator pins keep host-alias rejection covered.
2026-07-17 17:00:12 +01:00
rcourtman 72c409743d Warn when two machines share one Docker agent identity
Cloned VMs that keep the same /etc/machine-id collapse into a single
Docker host in Pulse, with each clone's report silently overwriting the
other (#1584). The server now tracks per-identity hostname and machine
ID observations and flags a conflict when a value flaps back to one
already seen inside a 15-minute window, a signature a one-time rename
never produces. The conflict rides the DockerHost model through unified
resources, and the Docker page shows a warning naming the flapping
hostnames with the machine-id remedy. The warning self-clears once one
clone stops reporting for the window.
2026-07-16 20:55:09 +01:00
rcourtman e3382c8bcb Use authoritative Docker OOM evidence 2026-07-15 17:55:26 +01:00
rcourtman 71a3b6ebcd Restore release-blocking backend contracts 2026-07-13 21:51:33 +01:00
rcourtman 4aac79dc72 Add durable agent operation receipts 2026-07-12 04:16:22 +01:00
rcourtman e77ab9518d Add safe APT workflow foundations 2026-07-12 02:53:01 +01:00
rcourtman 82c7c52727 Expose server-authored action policy provenance 2026-07-12 00:18:43 +01:00
rcourtman b7b897651b Add canonical action result truth 2026-07-11 21:27:00 +01:00
rcourtman cd7886aa44 Enforce server-owned action approval authority 2026-07-11 19:49:17 +01:00
rcourtman 71ea14e4dd Add durable action dispatch continuity 2026-07-11 16:08:44 +01:00
rcourtman c74c88fb86 Fix dispatch-time policy revocation 2026-07-11 14:29:26 +01:00
rcourtman e65bef8e84 Fix atomic action lifecycle replay 2026-07-11 14:02:32 +01:00
rcourtman eb9954618a Add governed storage pressure cleanup 2026-07-11 10:11:35 +01:00
rcourtman 1312da3acb Add governed host update autonomy 2026-07-11 01:25:14 +01:00
rcourtman 94ccc7a0c2 Close the 2b residuals on the typed Patrol proposal seam
Proposals now require their full correlation identity before anything
persists: a Submit without a finding ID or investigation ID is refused,
so a planned action can never lose the deterministic link back to its
Patrol finding. Pinned in the plan-only broker contract test.

The persisted-state transition callback becomes org-scoped
(OnActionTransition func(orgID, record)) and is wired through
ResourceHandlers.SetActionTransitionPublisher into the shared lifecycle
service, so a multi-tenant Patrol reconciler can key per-tenant stores
and can never apply a transition to the wrong tenant. Publication still
strictly follows persistence; code-standards pins guard the org-scoped
signature and wiring.

pkg/aicontracts/action_broker.go gains machine ownership: a shared
ai-runtime/api-contracts registry boundary (owned_files plus a sorted
shared_ownerships entry) with path policies proving through
pkg/aicontracts/contracts_test.go, and Shared Boundaries entries
inserted in canonical sorted order in both contracts.

Slice 2b-1 of the typed-lifecycle ratchet; the Patrol reconciler itself
lands with the orchestrator wiring now that ai_handlers.go is free.
2026-07-10 12:43:17 +01:00
rcourtman f356994869 Extract the transport-independent action lifecycle service
Planning, approval decisions, and execution for typed resource actions
move out of the HTTP handlers in internal/api/actions.go into a new
internal/actionlifecycle.Service owned by api-contracts. The REST
handlers become thin decode/actor/error-mapping adapters over the one
shared service, and ResourceHandlers.ActionLifecycle() exposes the same
service for in-process consumers, so a future Patrol action broker
inherits identical resource lookup, availability checks, plan hashing,
audit persistence, remediation locks, plan-drift revalidation,
execution, and terminal publication instead of loopback HTTP or a
parallel lifecycle.

Behavior is preserved: same status codes, error codes, and audit/
lifecycle persistence ordering, backed by the existing api contract
tests plus new fail-closed proofs for the service itself (unknown
resource/capability, availability refusal, unapproved execution,
remediation lock, plan drift, missing executor, missing store).

Contract text in api-contracts, agent-lifecycle, and storage-recovery
now names the service alongside actions.go and planner.go; the
subsystem registry owns internal/actionlifecycle/ under api-contracts
with a dedicated path policy; the code-standards and contract source
pins follow the moved invariants; and the subsystem_lookup line-number
pin shifts with the api-contracts canonical-files list insertion.

This is the first slice of making the typed action lifecycle the only
autonomous execution route for Patrol, Assistant, and MCP.
2026-07-10 11:06:55 +01:00
rcourtman 0fa841f66f Improve monitor-first attention states 2026-07-09 21:29:45 +01:00
rcourtman 74131e56e3 Fix no-op relationship_change spam from registry rebuilds
Every state update rebuilds the resource registry from scratch, which
reconstructs all relationship edges with fresh ObservedAt/LastSeenAt
stamps and fresh metadata maps. recordRegistryChanges compared the old
and new slices with reflect.DeepEqual, so every relationship-bearing
resource emitted a relationship_change row on every rebuild cycle even
when nothing changed. On the public demo this wrote roughly 450k rows
per day (1.2M of 1.6M rows were literal from==to no-ops), grew
unified_resources.db to 1.6GB in three days, starved the store's single
connection until retention pruning failed with SQLITE_BUSY, and drove
the droplet into the swap-thrash outage on 2026-07-08. Same mechanism
as issue #1496.

Compare relationship sets by edge identity instead: canonical source,
canonical target, type, and active state, order-insensitive. Volatile
provenance fields no longer count as change.

Also cap resource_changes at 200k rows during retention pruning so a
pathological writer can never grow the table unbounded inside the
30-day retention window, and record both invariants in the
unified-resources subsystem contract.
2026-07-08 08:10:15 +01:00
rcourtman b1fdefdd50 Normalize Docker container CPU capacity
Refs #1293
2026-07-03 11:51:08 +01:00
rcourtman 7c75b13d2c Carry host power sensor readings 2026-06-30 10:02:49 +01:00
rcourtman d393ccf310 Add typed NVIDIA GPU stats 2026-06-30 09:43:33 +01:00
rcourtman ccf90bb26d fix: resolve 4 pre-existing test failures blocking clean CI
1. Regenerate pulse-mcp README from canonical manifest (doc drift)
2. Add 31 missing Pulse Intelligence telemetry fields to both PRIVACY.md
   copies to match current Ping struct JSON tags
3. Rebuild portal frontend bundle to update build_manifest.json hash
4. Update action execution contract test to match current code structure
   (handler wrapped with withExternalAgentCapabilityActivity, error codes
   referenced via agentcapabilities constants instead of literal strings)

Full Go test suite now passes clean: 126 packages, 0 failures.
2026-06-26 13:30:00 +01:00
rcourtman 62c2b765d0 feat: attach availability checks as facet on known resource row
Agentless availability checks (ICMP/TCP/HTTP) were always minting
standalone network-endpoint resources, leaving them disconnected from
the known Proxmox/Docker guest they actually monitor. This made
availability evidence invisible on the platform resource row where the
user expects it, per the performance-and-scalability bounded-row
contract.

Backend (unified-resources ingest):
- Add LinkedResourceID field to AvailabilityData and AvailabilityTarget
- resolveAvailabilityLink: explicit link first, then exact-IP unambiguous
  correlation; skip hostname-only (lossy); guard against overwriting a
  different target's facet
- Unlinked/unmatched probes still mint network-endpoint (fallback)

Frontend:
- Relax getAvailabilityProbePresentation for any resource with availability
- Add compact protocol badge to UnifiedResourceHostTableCard name cell
- Add optional 'Link to resource' field to availability target form
- Add linkedResourceId to frontend types

Contracts: api-contracts, unified-resources, monitoring,
performance-and-scalability, storage-recovery.

Governance: coverage_gap + candidate_lane in status.json.
2026-06-26 12:16:11 +01:00
rcourtman 6a162a1736 Add macOS thermal state reporting
Report Darwin pmset pressure separately from Celsius readings and carry it through host sensor state and resource details.
2026-06-14 11:07:47 +01:00
rcourtman 2a33c3a09a Add Docker action readiness reasons
Refs #1034
2026-06-12 23:58:24 +01:00
rcourtman 53a05ccb7c Fail closed Docker and Podman actions without agents
Refs #1034
2026-06-12 22:42:16 +01:00
rcourtman 6725d6a784 Add governed Docker and Podman lifecycle actions
Refs #1034
2026-06-12 21:17:58 +01:00
rcourtman b53e1a3e0e storage(pools): carry the full ZFS pool payload to the storage surface
The unified-resource adapter flattened models.ZFSPool to four scalars
(state + R/W/C totals), so scan status and the per-device report never
reached the frontend. The storage detail's ZFS card, the usage bar's
scrub/resilver overlay and ZFS tooltip, and ZFS-device-to-disk matching
were all dead code on the unified path: a degraded pool rendered as a
one-word State cell with no way to see which device failed or that a
resilver was running. Found by the v5-parity audit of the pools table
(same pipeline disease as #1471 on the disks table).

- Add StorageMeta.ZFSPool and populate it in resourceFromStorage
  (normalized copy, not aliased).
- Serialize it in monitorStoragePlatformData so the /api/state path
  carries it alongside the existing flat scalars.
- Map it through normalizeStorageMeta and the storage record adapter
  (meta first, flat platformData fallback).
- Render the per-device report (name, vdev type, state, R/W/C errors,
  message) in the detail's ZFS Pool card - the v6 home for what v5
  showed via the health-map dots and the degraded-pool warning row.
- Pin the end-to-end path in code_standards_test and update the
  unified-resources, monitoring, storage-recovery, and
  frontend-primitives contracts.

Verified live in mock mode: degraded pool now shows the resilver scan,
pool error totals, per-device states, and the bar pulse overlay.
2026-06-11 16:48:57 +01:00
rcourtman a43f7cbe7f Add discovery readiness to Assistant context 2026-06-04 21:56:36 +01:00
rcourtman 0d0eb4bf11 Stabilize v6 release dry-run backend gate 2026-06-03 18:12:42 +01:00
rcourtman 3e61849242 Drop standalonePageModel snippet from agentless contract test; bump test timeout to 20m
TestAgentlessAvailabilityTargetKindStaysCanonical was pinning the
former agentless-machine classification in
frontend-modern/src/features/standalone/standalonePageModel.ts
(resource.availability?.targetKind,
availabilityTargetKindFor(resource) === 'machine'). Commit 1e16cf34f
intentionally narrowed the Machines surface to Pulse Agent resources
only, removing that classification, but did not update the test. The
server-side contract for availability targetKind across
config/availability.go, monitoring/availability_poller.go, types.go,
and frontend-modern/src/api/availabilityTargets.ts is preserved and
still pinned by the same test for any future consumer.

Makefile go test timeout bumped from 10m to 20m. The rc.5 backend
test run cleared 10m with slack; the rc.6 backend test run hit 13m
in internal/api before the binary panic-killed itself. 20m gives
headroom without hiding regressions for the rc.6 release path while
the package-size growth is tracked separately.
2026-05-27 17:17:13 +01:00
rcourtman bfafe559f6 Classify agentless machine availability targets 2026-05-25 21:38:43 +01:00
rcourtman 5016cbc2ba Add vSphere network inventory
Project vCenter network inventory through canonical resources and add the vSphere Networks table backed by vCenter network topology. Align resource presentation coalescing so state and resource APIs share the same host contract.
2026-05-22 20:26:56 +01:00
rcourtman 6c7d64ae43 Carry vSphere cluster services
Project vCenter cluster HA and DRS service state through the VMware resource facet so existing hosts and VMs expose cluster posture as read-only topology context.
2026-05-22 19:18:46 +01:00
rcourtman 9f98f8fcb9 Carry vSphere VM hardware config
Project vCenter VM hardware, CPU, memory, and boot configuration through the VMware resource facet and shared vSphere details so operators can inspect virtual hardware posture as read-only monitoring context.
2026-05-22 18:54:36 +01:00
rcourtman add3984f25 Carry vSphere VMware Tools status
Project vCenter VMware Tools runtime facts through the VMware resource facet and vSphere VM surface so operators can see Tools run state, version posture, upgrade policy, install attempts, and guest reboot requests as read-only monitoring context.
2026-05-22 18:22:49 +01:00
rcourtman 10c3c66f92 Carry vSphere VM virtual disks
Project vCenter VM hardware disk facts through the VMware resource facet and vSphere VM surface so operators can see virtual disk backing, capacity, datastore, and bus placement as read-only monitoring context.
2026-05-22 16:45:08 +01:00
rcourtman 6a7936ba4e Carry vSphere VM network adapters
Project vCenter VM hardware Ethernet adapter facts through the VMware resource facet and vSphere VM surface so operators can see vNIC backing network, MAC address, connection state, and adapter flags as read-only monitoring context.
2026-05-22 15:40:25 +01:00
rcourtman 3cd1517883 Surface vSphere activity timeline
Add a global resource timeline endpoint for provider activity and wire vSphere Activity to VMware timeline changes. Seed mock VMware activity through the same supplemental-change path and keep the relevant resource contract tests current.
2026-05-22 08:54:43 +01:00
rcourtman 0c9ea7504e Normalize inactive Docker Swarm evidence 2026-05-17 18:45:24 +01:00
rcourtman d3670d7882 Redact legacy action audit verification details 2026-05-13 21:50:56 +01:00
rcourtman 8b0f3564f6 Fail closed on stale API action plans 2026-05-12 17:32:11 +01:00