Commit Graph

8480 Commits

Author SHA1 Message Date
rcourtman f16a7f4d7d Record commercial proof approval boundary 2026-07-21 23:57:45 +01:00
rcourtman dc25f20cfd Record executable commercial floor proof 2026-07-21 23:49:43 +01:00
rcourtman be0ef26d16 Supersede unsafe commercial rehearsal outline 2026-07-21 23:26:12 +01:00
rcourtman d6fa623035 Compose ESXi hosts as members of their owning vCenter connection
One vCenter connection spans many ESXi hosts, so the Infrastructure source
row now lists them the way Proxmox cluster rows list their nodes: an
expandable member list with per-host state, aliases, and last-seen. Members
are API-side composition only — no primary marker, no agent connection, and
the member subtitle reads 'vSphere host' instead of cluster-node wording.
TrueNAS keeps no member composition because that connection monitors exactly
one machine.

Mock mode now feeds its vCenter and TrueNAS fixtures into the connections
aggregator (only when no real instances are configured), so the mock ledger
shows the same platform source rows a real deployment would instead of
omitting vSphere and TrueNAS entirely.
2026-07-21 23:09:29 +01:00
rcourtman 278820283c Record commercial rehearsal CLI validation
Contract-Neutral: Evidence-only commercial rehearsal record; unrelated runtime files and shared index belong to another active task
2026-07-21 23:03:59 +01:00
rcourtman 77cfa9f1e4 Record fail-closed commercial event rehearsal 2026-07-21 22:53:52 +01:00
rcourtman 536a845c7a Record commercial reconciliation evidence 2026-07-21 22:39:42 +01:00
rcourtman 43bb95a406 Integrate SignPath Windows release signing 2026-07-21 22:34:00 +01:00
rcourtman 9e8bcd23fe Stop fabricating ledger agent rows for integration-monitored machines
vSphere ESXi hosts and TrueNAS boxes rendered as standalone rows under
'Pulse Agent hosts' in Infrastructure settings even though no Pulse Agent
runs on them. The rows were unmanageable duplicates of their owning platform
connection: they carry no credentials, pause, or remove semantics, and they
can never attach to their vSphere/TrueNAS system because attachment requires
a shared host while the machine hostname differs from the vCenter address.
They also inflated connected-system counts.

buildConnections now skips hosts with a non-empty IntegrationSource, so the
ledger and grouped systems represent those machines solely through their
owning platform connection. Per-machine visibility is unchanged on the
vSphere/TrueNAS platform pages and Machines, which read the unified fabric
directly. Connection.integrationSource stays declared as defense-in-depth
for agent-only client workflows. No alert impact: agent-type rows were
already dropped from alert snapshots.
2026-07-21 22:11:46 +01:00
rcourtman 7354d8d19f Keep integration-monitored machines out of Agent Doctor and surface workload-only agents
The connections ledger derives agent rows from the unified fabric, which
includes machines whose telemetry comes from platform integrations (vSphere
ESXi hosts, TrueNAS). Agent Doctor rendered every one as a permanent
'Unknown / no structured reason' row, while agents the ledger does not carry
(Docker-only, Kubernetes-only) were silently dropped from the fleet view.

- Expose HostView.IntegrationSource() (source-set based: only SourceAgent
  ingest counts, since integration providers fabricate an Agent payload) and
  plumb it through models.Host to the connections ledger as the optional
  integrationSource field.
- Agent Doctor skips integration-backed connections and appends
  diagnostics-only agents, honoring scope, so the doctor covers exactly the
  real Pulse Agent fleet.
- Update readiness agent checks no longer count integration-backed machines
  as registered agents.
- Humanize doctor copy: plain-language stale message with '10m 2s'-style
  durations, offline wording without enum leakage, no 'Supported target:
  Unknown' cell when no target is published, host-local command banner only
  when a command is actually offered, and a compact non-zero summary strip.

Contracts updated for unified-resources, monitoring, api-contracts,
agent-lifecycle, and dependent storage-recovery; verification via
views_test.go, monitor_host_agents_test.go, state_host_test.go,
contract_test.go, and the frontend connections API test.
2026-07-21 21:24:15 +01:00
rcourtman 963401ac90 Let metrics reads run concurrently with writes instead of queueing
The metrics store capped its SQLite pool at one connection, so every UI
history read queued behind every buffered-write commit, and behind the
WAL checkpoints those commits pick up at the 4000-page threshold. On
write-heavy installs (many Docker agents with churning containers) that
serialization presented as sustained 120-260ms COMMIT warnings and an
unresponsive UI even with idle CPU and fast disks. Writes were never the
risk: flush, rollup, retention, and maintenance already funnel through
the single background worker goroutine, and the WriteBatchSync poller
path serializes on the WAL write lock via busy_timeout.

Raising the pool exposed a second bug: auto_vacuum(INCREMENTAL) in the
per-connection DSN pragmas replays as a database-header write whenever
the pool opens a new connection, which blocks connection creation behind
the active writer for up to the full 30s busy_timeout. auto_vacuum is a
persistent database property that migrateAutoVacuum already establishes
once at startup, so the per-connection copy is dropped.

Refs #1601

Contract-Neutral: behavioral fix: metrics store read concurrency and per-connection auto_vacuum pragma removal, no public contract delta (#1601)
2026-07-21 20:55:41 +01:00
rcourtman 0e6fa57c08 Normalize Proxmox-reported disk health to the canonical vocabulary
PVE's disks/list endpoint labels healthy SCSI/SAS drives OK while ATA
drives say PASSED, and failing ATA drives come back as FAILED! with the
bang. Pulse ingested those raw strings, so a healthy SAS drive rendered
as health Unknown even though the Proxmox UI showed S.M.A.R.T. OK. The
host agent and TrueNAS paths already normalize their health text; the
PVE ingestion was the only entry that did not.

Map OK/PASS to PASSED and FAIL-containing values to FAILED at ingestion,
and accept OK as healthy in the disk presentation layer as defense for
state produced by older servers.

Refs #1595

Contract-Neutral: behavioral fix: normalize PVE disk health strings at ingestion, no public contract delta (#1595)
2026-07-21 20:30:54 +01:00
rcourtman 38ecb2e1a0 Document how the Enterprise multi-tenant license is obtained
The requirements table named an Enterprise license but the pricing page
only sells Community, Relay, and Pro, leaving no visible path to the
capability. A Pro buyer purchased today expecting multi-org on the
strength of this doc. State plainly that the self-serve tiers do not
include the capability and where to ask for Enterprise licensing.

Contract-Neutral: docs-only: state how the Enterprise multi_tenant license is obtained; no runtime change
2026-07-21 18:35:32 +01:00
rcourtman 59e6f25a65 Detect SAS transport and parse SCSI attributes in SMART collection
smartctl reports SAS drives with device protocol SCSI, so detectDiskType
fell through to its blanket sata default, and that non-empty type also
masked the text-output transport evidence the fallback parser had
already extracted. The wrong sata label then blocked the merge layer
from promoting the smartctl serial over the SAS transport address
Proxmox reports.

Classify SCSI-protocol devices via the scsi_transport_protocol
descriptor, let the text and sysfs refinements upgrade a generic scsi
label, and apply the legacy sata default only after all evidence is
exhausted. Parse the SCSI log-page fields (power-on hours, grown defect
count, endurance used) that SCSI drives report instead of an ATA
attribute table, and let agent-reported sas replace coarse hdd/ssd/sata
types during the disk merge.

Refs #1595

Contract-Neutral: behavioral fix: SAS transport detection and SCSI attribute parsing in host agent SMART collection; no public contract delta (#1595)
2026-07-21 17:36:14 +01:00
rcourtman 7f2fb03380 Restore manual agent update commands unless an update is actively applying
Agent Doctor withheld the manual update command whenever an eligible
agent had auto-update on and an update pending, including agents idle
until their next scheduled check or stuck mid-convergence, leaving no
manual escape hatch. Block the command only while the updater reports
state updating with a fresh attempt timestamp, and restore it once an
in-flight attempt is older than ten minutes.

Refs #1564

Contract-Neutral: behavioral fix: Agent Doctor manual command gate now blocks only live in-flight updates; no public contract delta (#1564)
2026-07-21 17:24:15 +01:00
rcourtman 6b1dee576e Resolve mangled patrol assessment IDs against active findings
Patrol's verdict contract required the model to echo finding IDs like
update-analysis-docker:<uuid>/<64-hex-digest> exactly. Smaller models
(reported with Gemini 2.5 Flash-Lite) drop the key prefix or digest
tail, every patrol_assess_finding call fails, and the whole run ends
with 'Patrol finding assessment incomplete'. Resolve an ID that
unambiguously identifies one active in-scope finding (case-insensitive,
prefix, or separator-suffix match), record the canonical ID so the
verdict accounting and duplicate guard still hold, and list the valid
active IDs in the lookup error so the model can self-correct instead of
guessing. Hallucinated or ambiguous IDs still fail closed.

Refs support report from Johannes Strasser, 2026-07-20

Contract-Neutral: behavioral fix: tolerant patrol assessment ID resolution for weak models; fail-closed contract unchanged
2026-07-21 15:13:43 +01:00
rcourtman d7a0d97fa2 Subscribe workloads guest metadata to the canonical metadata event
The workloads metadata state still listened for the legacy
pulse:metadata-changed event, which no code dispatches since URL saves
moved to dispatchResourceMetadataChanged, and its handler rewrote
3-part canonical guest ids into the v5-era instance-vmid shape that no
lookup uses. In-page saves only stayed live through the drawer's direct
callback; any other dispatcher was invisible. Listen for
pulse:resource-metadata-changed and apply updates under the dispatched
metadata id, ignoring agent-kind events that never key workload rows.

Refs #1556

Contract-Neutral: behavioral fix: workloads metadata state listened for a legacy event nothing dispatches; no public contract change (#1556)
2026-07-21 14:35:10 +01:00
rcourtman e339af2a6e Order physical interface IPs ahead of virtual bridges in host identity
Agents report network interfaces sorted by name, which places docker0
and br-* bridges ahead of eth*/en* interfaces, and every consumer of
ResourceIdentity.IPAddresses treats the first entry as the host's
primary address. Docker hosts therefore showed a 172.x bridge IP in
the Machines and Docker tables instead of the machine's LAN address.
Collect physical-looking interfaces first so bridge and overlay
addresses never lead the list.

Refs #1529

Contract-Neutral: behavioral fix: order physical interface IPs before virtual bridges in identity collection; no public contract change (#1529)
2026-07-21 14:27:48 +01:00
rcourtman ef4f204d25 Make report branding PDF assertion case-insensitive
Treat extracted PDF presentation casing as non-semantic while preserving exact resource identity and cross-client branding exclusion checks.
v6.1.0-rc.4
2026-07-21 10:23:06 +01:00
rcourtman ea664843ba Align prerelease dry-run signing requirements
Keep macOS notarization mandatory for every release candidate while requiring Windows Authenticode only for stable promotion, matching the publish workflow and RC4 release packet.
2026-07-21 09:17:39 +01:00
rcourtman 4f6179368a Add branch-coverage tests for unifiedresources helpers, smartctl targets, intent-policy manager
Covers previously-uncovered pure/near-pure functions from the recent
alert-intent and disk-inventory source drop:

- unifiedresources registry seeded K8s identity/source-id builders
  (cluster/node/pod/deployment/typed) and VMware/proxmox/predicate
  helpers (seededVMwareSourceID, proxmoxGuestFallbackSourceID,
  isDockerNetworkAttachmentRelationship, physicalDiskTopologyCompatible)
- unifiedresources ActionPolicyAuthorizationDigest (digest-excluded
  invariant) and normalizePair ordering invariant
- hostagent smartctlTargetsFromDevices
- alerts Manager UpdateIntentPolicies (validation / nil / revision
  conflict / success), GetIntentPolicies, SetBackupIntentContextResolver

All 13 target functions move 0% to 100% under the new tests; test-only,
no source changes.
2026-07-21 06:14:26 +01:00
rcourtman 4f43878ebb Add focused branch coverage and repair infrastructure source contract
Contract-Neutral: test-only coverage and source-contract assertions; no runtime or contract behavior changed
2026-07-20 22:41:19 +01:00
rcourtman 9f9e02e811 Refuse dispatch when action readiness is lost 2026-07-20 21:44:59 +01:00
rcourtman 1eaffa9838 Run E2E checks on the v6 release branch 2026-07-20 21:09:09 +01:00
rcourtman d54fad623c Record Windows Patrol cold-start qualification 2026-07-20 20:50:50 +01:00
rcourtman ed84c92da3 Add Patrol model readiness advisor 2026-07-20 20:45:39 +01:00
rcourtman 057cf74629 Add alert intent policies and delivery receipts 2026-07-20 20:27:39 +01:00
rcourtman e23f19459d Add Agent Doctor fleet diagnostics workflow 2026-07-20 19:53:34 +01:00
rcourtman cee4f64614 Complete trust-gate governance contracts 2026-07-20 17:43:01 +01:00
rcourtman a70e285c4f Fall through server-error probes in vSphere release negotiation
vCenter answers a newer-than-supported vim25 release path with 404 on
some builds but HTTP 500 on others: 8.0.x returns 500 for the 9.0.0.0
service-content probe. The negotiation loop only continued on
not_found, so it aborted on the first probe and never tried the 8.0.3
release the server actually speaks, failing the connection test with
'vi-json service content request failed with HTTP 500'.

Continue the probe loop on generic endpoint failures as well as 404;
still abort immediately on auth, permission, TLS, and network errors,
which no release string can fix.

Fixes #1596

Contract-Neutral: behavioral fix: vSphere release negotiation falls through HTTP 500 probe responses (issue #1596); no public contract delta
2026-07-20 16:37:22 +01:00
rcourtman a4d800fe3e Keep platform CPU authoritative on hypervisor-managed guests
An agent running inside an LXC measures /proc through the shared kernel
and reports the node's utilisation, not the container's. Because
SourceAgent outranked SourceProxmox in the metric merge, that value
overrode the hypervisor's cgroup-accounted CPU on the guest's canonical
resource, so the workloads row disagreed with the (Proxmox-sourced)
history chart by orders of magnitude on idle guests.

Demote agent-sourced utilisation metrics below the platform source when
the target resource is a hypervisor-managed guest (vm /
system-container). The freshness gate still lets a live agent cover for
a stale platform source.

Fixes #1597

Contract-Neutral: behavioral fix: demote in-guest agent utilisation below platform source on hypervisor-managed guests (issue #1597); no public contract delta
2026-07-20 16:34:58 +01:00
rcourtman b6a74576bc Integrate trust-gate reliability fixes 2026-07-20 16:03:29 +01:00
rcourtman fbebdddb7d Add frontend branch-coverage tests for eight untested pure models
A full V8 branch-coverage regen (18326-test suite clean, so the counts are
ground truth) flagged eight pure frontend modules as the only remaining
defensible coverage gaps. This adds one branchcov test per module, exercising
genuinely-untested exported functions and previously-uncovered branch arms.

Modules and targets covered.
- utils/agentInstallCommand buildPowerShellInstallScriptBootstrap, a
  completely untested export, plus its empty-URL throw arm
- i18n/locales resolveSupportedLocale across all four resolution strategies
  and the unsupported-base null arm, plus getLocaleFallbackChain
- shared/helpIconModel calculateHelpPopoverPosition geometry (top and bottom
  flip arms, horizontal clamp) and resolveHelpContent
- Workloads/workloadsFilterModel countActiveWorkloadsFilters across all eight
  filter arms and hasActiveWorkloadsFilters
- Workloads/metricBarModel buildMetricBarPresentation showLabel and
  showSublabel threshold arms
- shared/selectionCardGroupModel variant and tone resolvers and the class helpers
- shared/animatedNumberModel sanitizeAnimatedNumberValue non-finite arm
- shared/tagInputModel getTagInputPlaceholder arms, getNextTagsAfterRemove,
  canAddTag

Tests only, no source changes. 173 new test cases, all green. tsc and eslint clean.
2026-07-20 14:22:43 +01:00
rcourtman 674b70a02a Add Go branch-coverage tests for remaining monitored-system selector matchers
Test-only (GLM nightly grunt, round 2): new
monitored_system_projection_matchers2_branchcov0720am_test.go covering the
previously-uncovered Docker/TrueNAS/PBS/VMware per-type replacement-selector
matchers and the monitoredSystemReplacementSelectorMatches dispatcher in
internal/unifiedresources. Each per-type predicate drives its nil-source guard,
every OR-chain arm in isolation, no-match, and whitespace-only; the dispatcher
drives each DataSource route plus the unmatched arm. Complements the round-1
Agent/Proxmox/PMG/K8s coverage. No source changed; contract-neutral.
2026-07-20 11:08:29 +01:00
rcourtman a1eb3e9fe5 Dedupe latest-action-audit lookups behind a match-predicate helper
GetLatestActionAuditByOrigin and GetLatestActionAuditByOperationalRecord
were token-for-token identical except for which Origin field they matched,
tripping golangci-lint's dupl check. The scan/latest-selection/clone logic
now lives in latestActionAuditMatching(match); each getter keeps only its
input trimming and predicate.

Contract-Neutral: dupl lint dedup: extract shared latestActionAuditMatching helper, behavior identical, no public-contract delta
2026-07-20 10:56:22 +01:00
rcourtman 639e88104c Demote operational-trust protection posture spec to probation
tests/90-operational-trust-protection-posture.spec.ts failed the
stable tier on main in run 29731882505 — the first tiered run. One
incident on main demotes: it rejoins the gate after 10 consecutive
green runs, per the rule above PROBATION_SPECS.

Contract-Neutral: probation demotion per documented tier rule: spec 90 failed on main run 29731882505; CI gating list only, no dev-runtime delta
2026-07-20 10:55:07 +01:00
rcourtman 325e7f5bb2 Add Go branch-coverage tests for unified-resource pure helpers and platform fixtures
Test-only wave (GLM nightly grunt): new *_branchcov0720am_test.go files raising
branch coverage on previously-uncovered pure value-in/value-out functions. No
source changed; contract-neutral.

internal/unifiedresources (10 files):
  monitored_system_projection selector matchers (Agent/Proxmox/PMG/K8s),
  physical_disk risk classifier + metric-id builder, availability lookup,
  monitored_systems reason/suffix helpers, action refusal classifier +
  human-action-binding validation, action auto-authorization class
  validate/normalize, host APT digest validator, patrol-autopilot stored-evidence
  validation, canonical governance metadata projection, top-level identity basis.
internal/platformsupport: host-identity token/profile lookup + deep-copy safety.
internal/vmware: fixture activity-change projection + connection-error guard.
internal/mock: discovery-fixture type/target filters.
internal/mockruntime: startup-enabled env gate.

Each new test drives every distinct branch (nil/empty, each conditional arm,
error sentinels via errors.Is, and returned-copy independence) and verified
0%->covered on its target functions. Two named functions were intentionally
left uncovered as branchless (ActionPolicyAuthorizationDigest; the default-build
ValidateEnablement, whose branchy twin sits behind the release build tag).
2026-07-20 10:49:11 +01:00
rcourtman d89e3e3163 Add staged-file prettier formatting to pre-commit
New scripts/release_control/format_staged_frontend.py mirrors the staged
Go formatter: formats staged frontend-modern/src {ts,tsx,css,json} blobs
through prettier --stdin-filepath, writes results back to the index
directly (no broad restaging), syncs the worktree only when it matches
the previously staged content, and iterates to a fixed point to absorb
prettier's occasional non-idempotence. Skips gracefully when prettier is
not installed (fresh clones, linked worktrees without node_modules).
Wired into .husky/pre-commit after the Go formatter, with unit tests in
the governance battery, a README note, and a .gitignore allowlist entry.
With the one-time sweep in the previous commits, prettier drift can no
longer re-accumulate and make format stays clean on a clean tree.
2026-07-20 10:44:36 +01:00
rcourtman 3a6a6f6825 Finish prettier sweep: two straggler test files
settingsArchitecture.test.ts picked up an unformatted hunk in the
guardrail prep edit; helpers.branchcov2.test.ts needed a second prettier
pass to reach a fixed point. prettier --check over frontend-modern src
is now fully clean.
2026-07-20 10:44:36 +01:00
rcourtman 0e6d0532bf Format frontend-modern/src with prettier (mechanical, no functional changes)
One-time sweep: npx prettier --write "src/**/*.{ts,tsx,css}" over
frontend-modern, clearing 611 files of accumulated drift so make format
no longer spuriously dirties the tree. Verified format-only: tsc
--noEmit clean and the full vitest suite green (18326 passed) after the
sweep. A staged-file prettier step lands next to keep drift out.

Contract-Neutral: mechanical prettier formatting sweep, zero behavioral or contract delta (tsc clean, full vitest suite green)
2026-07-20 10:44:35 +01:00
rcourtman 84c7667305 Make source-text guardrail assertions tolerant of prettier wrapping
settingsArchitecture and WorkloadsSurface.performance.contract pin exact
source text (JSX copy phrases, a single-line export list) that prettier
line-wraps at printWidth 100. Normalize whitespace for the copy-phrase
guards and match the export list with a wrapping-tolerant regex so a
formatting pass cannot break them. Prep for the repo-wide prettier sweep.
2026-07-20 10:44:34 +01:00
rcourtman f2fa92f576 Split Core E2E into gating stable and non-gating probation tiers
Mined per-spec failure data from the 32 completed Core E2E main runs
since the 2026-07-18 quarantine delist (failed-shard logs; a green
shard means every spec in it passed). 26 specs failed or retry-flaked
within the 10 most recent completed runs; they seed PROBATION_SPECS in
tests/integration/playwright.config.ts. The remaining 62 files form the
stable tier and are the only specs that can fail the e2e-verdict job.

Mechanism extends the existing quarantine list rather than adding a
parallel one: PULSE_E2E_TIER=stable ignores probation specs,
PULSE_E2E_TIER=probation runs only them, unset runs the full suite
(local behavior unchanged). CI runs both tiers per shard against the
same containers; the probation pass sits behind continue-on-error with
its own report/results dirs and artifacts, so a probation flake is
reported in the shard summary without painting main red.

Promotion rule, documented next to the list: a probation spec promotes
to stable after 10 consecutive green main runs with no failure and no
retry-flake; one incident on main demotes a stable spec back. In the
newest completed run (29729544151) every failure was in a probation
spec — under this split that run's verdict is green.

Contract-Neutral: CI-only E2E tier split: gating semantics of push-CI verdict; local npm test behavior and dev-runtime orchestration unchanged, no public contract delta
2026-07-20 10:32:26 +01:00
rcourtman a12a82a46f Upload e2e artifacts only on failure with 3-day retention
Playwright HTML reports uploaded on every run at 30-day retention blew
the Actions storage quota (69.8 GB on 2026-07-20). Reports now upload
only when a shard fails, and all report/video/screenshot artifacts
keep a 3-day retention.
2026-07-20 09:54:57 +01:00
rcourtman 05c44f199f Stabilize populated browser fixtures
Contract-Neutral: Browser-only qualification fixture synchronization; no deployment or public runtime contract changes.
2026-07-20 09:47:03 +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 b858e7fd2d Stabilize shared browser qualification
Contract-Neutral: Browser qualification keeps the existing deployment, authentication, and mobile layout contracts while reusing the accepted test credential and avoiding a WebKit synchronous-layout probe.
2026-07-20 09:12:01 +01:00
rcourtman a65194de3a Stabilize mobile workload geometry probe 2026-07-20 08:42:01 +01:00
rcourtman 1153be4770 Keep agent install handoff on canonical config
Contract-Neutral: The first-session agent install handoff keeps the existing API and setup contracts while binding runtime handlers to the Router-owned canonical config through startup and monitor reloads.
2026-07-20 08:19:00 +01:00
rcourtman c73e78aeea Stabilize RC runtime ownership
Contract-Neutral: RC qualification fixes preserve existing public API, tenant, monitoring, and organization contracts while correcting canonical runtime ownership and test fixtures.
2026-07-20 07:50:22 +01:00
rcourtman 6eb559905d Reuse mock history seeds across tenants
Contract-Neutral: Reuse immutable mock-history seed work across tenant monitors without changing monitoring, tenant-isolation, or API contracts.
2026-07-20 06:30:55 +01:00