Count configured backup targets before the no-query check, preserve their accepted rows without renewing evidence, and publish incomplete provider history instead of reconciling unseen points away. Keep disabled storage unqueried; cover warm and rebuilt live state, one or all disabled targets, normal re-enable, confirmed empty reads and recovery.
Change-source: pulse-maintainer
Isolate Core's completed 7b633c75 repair from its obsolete containing
history. Preserve the contributor's twenty-second default and positive
whole-refresh override without logging raw invalid environment input,
with registered lifecycle, cancellation, cached-inventory and
serial-dispatch controls plus configuration guidance. Current VMware
runtime and test files still match the original parent exactly; preserve
all later unrelated contracts and documentation.
Original-contribution: https://github.com/rcourtman/Pulse/pull/3042
---
Fleet candidate `20261023T224436Z-delivery-trust` from the
`delivery-trust` lane. Reviewed tip
`00c1f53272243d1ddb6911a898212524c82d2495` on `main`.
[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
Isolate Core's completed 7b633c75 repair from its obsolete containing history. Preserve the contributor's twenty-second default and positive whole-refresh override without logging raw invalid environment input, with registered lifecycle, cancellation, cached-inventory and serial-dispatch controls plus configuration guidance. Current VMware runtime and test files still match the original parent exactly; preserve all later unrelated contracts and documentation.
Original-contribution: https://github.com/rcourtman/Pulse/pull/3042
Change-source: pulse-maintainer
The live interval setter deliberately schedules a catch-up poll. Test not-due admission with an already-configured interval and its retained completed-poll timestamp instead.
Change-source: pulse-maintainer
The namespace lifecycle test advances the root archive timestamp. A partial instance-wide scan must retain the two historical points and accept that new root point, not replace all root history. Assert every historical point remains byte-identical and exactly one independently accepted new point is present.
Change-source: pulse-maintainer
A capped snapshot cache can keep the same retained count after pruning
its newest archive. Require the group's newest timestamp to match
exactly before reusing it, so the deleted recent archive cannot keep
stale backups looking protected. Exercise VM and container polling
through successful, unavailable and denied refreshes, unchanged-cache
reuse, recovery and confirmed removal.
---
Fleet candidate `20261023T202016Z-core-runtime` from the `core-runtime`
lane. Reviewed tip `1d1bf942e63f8cdd8c9fe050822ef96cff75a516` on `main`.
[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
The fixture drives the real connection poll and therefore needs its ordinary poll-status map, in addition to backup scheduling and recovery state. Keep the new lifecycle proof independent of fixture setup panics.
Change-source: pulse-maintainer
Carry namespace discovery errors with the immutable datastore snapshot into background backup polling. Readable root history still updates, but unknown child namespaces cannot delete durable facts or claim complete protection. Cover real HTTP discovery through ingest, replacement state, repeated failures, scoped removal, recovery and legacy root-only support.
Change-source: pulse-maintainer
**Reproduce PVE partial-scan recovery history loss**
Drive ordinary backup polling through durable recovery ingest after live
inventory replacement, with partial, complete, isolation and
cancellation controls.
**Retain PVE recovery history across incomplete backup scans**
Use the poll's existing completeness evidence to admit destructive
reconciliation. Failed or skipped reads may update accepted rows without
deleting unseen durable facts, and cancellation cannot publish an empty
success. Complete deletions remain scoped and tested.
Contract-Neutral: Restore collection truth without changing APIs,
schemas, configuration or protection policy.
**Keep carried PVE rows from renewing recovery observations**
Retain their existing durable point evidence under the partial provider
observation instead of presenting a failed refresh as a fresh artifact
observation. Cover warm inventory alongside the cold-start
reconciliation regression.
Contract-Neutral: No API, schema, configuration or protection-policy
delta.
**Match the full workload identity in the PVE browser journey**
Use the production disclosure's guest name and VM identity, and bring
its provider evidence into the captured viewport. The initial selector
timeout is retained as a harness failure, not a product result.
**Avoid the published monitoring contract insertion conflict**
Relocate the PVE partial-backup collection contract without changing its
text so it composes with the published snapshot-listing contract at
15ea29fe2b. Runtime, regression tests and
browser-proof inputs remain unchanged.
---
Fleet candidate `20261023T194015Z-core-runtime` from the `core-runtime`
lane. Reviewed tip `d39d65fede2a6afc535c0387b0c0e6683868b22e` on `main`.
[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
A capped snapshot cache can keep the same retained count after pruning its newest archive. Require the group's newest timestamp to match exactly before reusing it, so the deleted recent archive cannot keep stale backups looking protected. Exercise VM and container polling through successful, unavailable and denied refreshes, unchanged-cache reuse, recovery and confirmed removal.
Change-source: pulse-maintainer
Retain their existing durable point evidence under the partial provider observation instead of presenting a failed refresh as a fresh artifact observation. Cover warm inventory alongside the cold-start reconciliation regression.
Contract-Neutral: No API, schema, configuration or protection-policy delta.
Change-source: pulse-maintainer
Use the poll's existing completeness evidence to admit destructive reconciliation. Failed or skipped reads may update accepted rows without deleting unseen durable facts, and cancellation cannot publish an empty success. Complete deletions remain scoped and tested.
Contract-Neutral: Restore collection truth without changing APIs, schemas, configuration or protection policy.
Change-source: pulse-maintainer
Drive ordinary backup polling through durable recovery ingest after live inventory replacement, with partial, complete, isolation and cancellation controls.
Change-source: pulse-maintainer
Treat every failed snapshot read as incomplete rather than interpreting 596 or unavailable text as an empty successful listing. Preserve known membership and warnings while independent accepted listings and confirmed removal continue normally. Correct the isolation fixture to use cluster-unique VMIDs, keeping the same-VMID cross-instance control.
Contract-Neutral: Restores existing failed-listing semantics for LXC; no public API, schema, configuration, identity or alert policy delta. Dedicated collection and producer/browser regressions are outside the registry's fixed verification filenames.
Change-source: pulse-maintainer
The monitor exposes models.Alert, not the internal manager alert type. Correct the fixture-only type mismatch before establishing the unchanged-runtime control.
Change-source: pulse-maintainer
Exercise both guest kinds, partial error results, same-VMID peer isolation, warning continuity, accepted removal and explicit disablement through the actual monitor. Include opt-in synthetic frames for the production alert consumer.
Change-source: pulse-maintainer
The mock update loop sights PVE nodes and their guests through ten fixed
cohorts, sized for the default two-second tick (every node within 20s).
The count did not follow PULSE_MOCK_UPDATE_INTERVAL, so the public demo's
15s tick sighted each node's guests only every 150s while the registry
judges Proxmox sightings stale after 60s. Within minutes most running
guests read as warning/telemetry_stale with proxmox source "stale", and
the Proxmox overview's Attention chip climbed to 64 of 77 guests.
Rotate the PVE estate through the largest divisor of the cohort count
that still sights every node within 30s, down to every node per tick. A
divisor keeps the loop's cohort index mapping each node to one tick per
rotation, and per-second churn never exceeds the two-second default. For
ticks slower than that budget, derive the mock Proxmox stale threshold
from the actual sighting cadence (mock.ProxmoxRefreshInterval), never
below the configured PVE derivation, the same way 1d9e66b24c derived the
supplemental provider thresholds.
Mock-only: real PVE polling rebuilds every guest of an instance with the
poll's sample time, and its threshold already derives from the poll
interval or the adaptive scheduler's maximum.
Use the canonical timestamp/value model directly from the shared retained
read engine. Preserve the full extrema reader, tier reconciliation, Docker
observation provenance, filters and chart sampling while eliminating unused
column transport and a second series copy.
Verify both projections, detached reads and chart sampling equivalence.
Record the measured memory reduction and retain inconclusive timing and
failed capacity evidence. The idle-worker 90 ms proof remains open.
Preserve selected memory freshness and the VM/LXC interpretation.
Retain both native tool contracts and current API concurrency controls.
Qualify this source separately from release and installed recovery.
Contract-Neutral: Integrate already-governed parents without a new contract change. Incoming verification files already match main. Fresh integration tests and source-bound browser proof cover the combined memory and installer surfaces.
Retain backup execution outcomes and collection coverage in each
organization's recovery store so provider inventory changes and restarts
cannot erase report evidence. Keep missing and incomplete history distinct
from an observed period with no attempts.
Reuse existing report scopes, calendar schedules, branding and delivery
recovery for client PDF and CSV reports. Register the paid renderer through
the existing private runtime boundary. Pricing and grants are unchanged.
VM inventory was available only as an on-demand download. It can now be
scheduled weekly or monthly as CSV, emailed or saved on the Pulse
server. Each attempt exports all current VMs in the organization,
including newly discovered VMs, through the existing exporter.
Historical performance-report limits and windows remain separate.
The schedule uses existing delivery configuration checks, persisted
success/failure/uncertain states, bounded retries and deliberate
recovery controls. Pricing, feature gates, retention entitlements and
existing customer grants are unchanged.
Live checks also reproduced two unattended inventory defects: reporting
retained a stopped monitor after configuration reload, and canonical
snapshot reads relied on dashboard reads to publish polled VM inventory.
Reporting now receives reload replacements through an atomic manager
reference. Canonical snapshot reads reuse the existing publication
boundary, including its freshness fast path, provider/mode fences and
nonblocking warm reads.
Validation:
- 105 focused frontend tests; full type check, lint, production build
and bundle budgets.
- Race checks for reporting, inventory, reload, publication and
organization isolation; clean private runtime build.
- Current runtime browser checks on `/settings/support/reporting` and
`/alerts/notifications` at 1440×1000, 820×844 and 390×844, with actual
pixel review. The first inventory read exports 61 normally polled VMs;
real MIME CSV matches the download; a newly discovered 62nd VM enters
the next export.
- Local SMTP acceptance, 451 retry across a real restart, permanent
rejection, uncertain acknowledgement and deliberate recovery; disk
delivery, edit/reload, disable, details and delete.
- Staged status, registry, contract, completion and exact-content
browser guards pass. Regression proof is registered against the specific
runtime paths it covers.
Reuse the canonical inventory exporter and report delivery workflow so
operators can email or save a current organization-wide inventory weekly
or monthly. Keep delivery checks, bounded retries and recovery states
shared, with existing pricing and customer entitlements unchanged.
Refresh the shared inventory for unattended reads and rebind reporting
after monitor reload so schedules use the current infrastructure state.
The agent-lifecycle and storage-recovery contracts now state that
registration, unregistration, node change and discovery events stay
with the organization that owns them. The tenant delivery tests move
into the proof files the canonical completion guard names for those
paths, and a route-level test covers the test-notification route's
authorization, method, payload and tenant delivery.
PULSE_METRICS_DB_PATH sets Config.MetricsDBPath, and GetMonitor builds
each non-default tenant from a deep copy of the base config, which kept
that path. monitoring.New then opened the same metrics.db for every
organization, so per-org charts, reports and Assistant summaries read
from one shared store.
Clear MetricsDBPath on non-default tenant configs so each org opens
metrics.db under its own data directory. Org deletion already removes
that directory, so its metrics go with it. The override still moves the
default org's database, which is the single-install case it exists for.
Since #2991 stopped guessing a PMG backup node from the connection name,
a failed `/config/cluster/status` read leaves no node to ask for
backups, and the poller still published that empty result.
`UpdatePMGBackups` replaces the instance's whole list, so one transient
cluster-status failure, or every node's backup read failing, wiped every
known PMG backup and the Backups view flapped empty until the next good
poll.
Only a node whose backup list was read is now authoritative for that
cycle. Nodes that were not read (every node after a failed cluster read,
a node whose backup read failed, or one a cancelled poll never reached)
keep their previous backups. This is the same per-scope carry the PVE
storage backup poller applies to failed storages
(`preserveFailedStorageBackups`). A node that answered with no backups,
or that a successful cluster read no longer lists, still clears its
entries. The failed read is still recorded as a poll failure. #2991's
rule against guessing node names is unchanged.
Tests in `monitor_pmg_test.go`: the three retention tests fail on main
and pass with this change. A complete enumeration that returns no
backups still clears the list.
The monitoring subsystem contract now records the carry (new section
"PMG backups keep last-known entries for unread nodes"), and the #2960
note no longer says a failed cluster read publishes an empty backup
list.
Replaces #3005, rebuilt on current main with the contract note.
The hub kept tenant-scoped delivery for state and alerts, but every
other event went through Broadcast/BroadcastMessage, which sent to all
connected clients. In a multi-tenant install a member of one
organization therefore received another organization's discovery
progress, discovered servers (addresses, ports, versions, hostnames),
node auto-registration and node-change events.
Discovery now carries the org of the monitor that owns it, and setup
and node handlers send through BroadcastMessageToTenant with the
request's org (the setup token's org for auto-registration). The
global BroadcastMessage accepts only instance-wide types (ping,
settingsUpdate, update:progress) and refuses everything else, so a new
caller cannot leak by default. Legacy clients without an org are
registered under the default tenant, so single-org installs receive
these events as before. The unused unscoped alert wrappers are removed.
Proxmox status/current sets agent=1 whenever the VM config enables the
QEMU guest agent (qemu-server vm_status: "QEMU Guest Agent is enabled in
config"), whether or not the in-guest service is running. Since
eb2424037d every successful status read renewed the guest-agent
fallback evidence on that flag, so a VM whose agent never answered kept
ten minutes of fallback eligibility after status/current later failed,
and Pulse sent filesystem and metadata guest commands that could only
time out.
Drop the status-flag renewal. Evidence is still renewed by a usable
filesystem reading and by useful guest metadata, and the original
observation age, canonical carry and every safety fence from
eb2424037d are unchanged. The new contract subtest polls with the real
integer agent flag: an enabled-but-silent agent admits no fallback
commands once status fails, while an agent that answered keeps its
fallback.
Since PMG stopped guessing a backup node from the connection name, a
failed cluster-status read leaves no node to ask, and the poller still
published the empty result. UpdatePMGBackups replaces the instance's
list, so one transient cluster failure (or every node's backup read
failing) wiped all known PMG backups and the Backups view flapped empty
until the next good poll.
Only a node whose backup list was read is now authoritative for that
cycle. Nodes that were not read, including every node after a failed
cluster read, keep their previous backups, the same per-scope carry
the PVE storage poller applies to failed storages. A complete read that
returns no backups, or a cluster listing that drops a node, still
clears them. The failed read stays recorded as a poll failure.
Commit a5baa7563b stopped Patrol reading cache-inclusive Proxmox memory
as guest pressure (issue #2762, a QEMU VM). It also put
`cluster-resources` in that cache-inclusive group for every guest type.
An LXC without a linked Pulse agent only ever gets `cluster-resources`,
so Patrol dropped memory pressure for all agentless containers:
- a container at 97% of its limit got no triage flag, forecast or
anomaly
- the seed said "guest pressure unknown; may include reclaimable cache"
- older memory alerts went to a billed model review on every run, and
any resolve verdict was thrown away
**That premise is wrong for LXC.** On both PVE 9 (`master`) and PVE 8
(`stable-bookworm` / `stable-8`), Proxmox subtracts page cache before
reporting a container's memory:
- `pve-common` `src/PVE/CGroup.pm` `get_memory_stat`: `$res->{mem} =
$mem - $stat->{file};` on cgroup v2 (`memory.current`), and `$res->{mem}
= $mem - $stat->{total_cache};` on v1 (`memory.usage_in_bytes`).
- `pve-container` `src/PVE/LXC.pm` `vmstatus` stores that value with
`$d->{mem} = int($mem->{mem});`. `PVE::LXC::CGroup` inherits
`get_memory_stat` from `PVE::CGroup` without overriding it.
- `pve-manager` `pvestatd` `update_lxc_status` writes `$d->{mem}` into
RRD field 8. `/cluster/resources` (`PVE/API2/Cluster.pm` →
`PVE::API2Tools::extract_vm_stats`) returns `$entry->{mem} = ($d->[8] ||
0) + 0;`.
A QEMU guest's listing `mem` is the host's view of guest RAM, which does
include the guest's cache, so it stays pressure-unknown.
**Change**
- `unifiedresources.QualifyGuestMemoryForKind` now takes the guest kind:
other platform, Proxmox VM or Proxmox container.
- A current, dated `cluster-resources` reading counts as known pressure
for a Proxmox container and stays cache-inclusive and unknown for QEMU.
- `status-mem`, `status-freemem` and `derived-total-minus-used` are
unchanged for every guest type.
- `GuestMemoryEvidenceForResource` takes the kind from the resource
type, so the Patrol inventory, the observer runtime and AI query
projections agree.
- `QualifyGuestMemory(bool)` keeps the conservative QEMU reading for
callers that don't know the guest type.
- The wrong comments in `calculateLXCMemory` and the LXC monitor tests
are corrected.
- Everything else in a5baa7563b still applies: retained, undated,
unknown and unavailable readings still cannot establish pressure or
recovery.
**Tests**
- `TestPatrolAgentlessLXCListingMemoryIsPressure` (new) builds an LXC
and a QEMU guest at 97%, both on `cluster-resources`, through legacy and
canonical read state. The LXC gets a memory triage flag and alert review
reads its value; the QEMU guest gets neither.
- `TestGuestMemoryClusterResourcesIsTypeAware` (new) covers both guest
kinds, retained readings, the other cache-inclusive sources and the
resource-type mapping.
- The `cluster-cache` fixture in `TestPatrolGuestMemoryEvidence` now
expects pressure for the container variant. It previously encoded the
wrong behaviour.
- Against origin/main's production files (`go test -overlay`), the new
and updated Patrol tests fail; with this change they pass.
Refs #2762
Supersedes #3011, which failed the documentation recipe test that pinned
the old `QualifyGuestMemory(` call in Patrol; this commit also updates
that pin to `QualifyGuestMemoryForKind(`.
Patrol treated every guest's cluster-resources memory as cache-inclusive,
so an LXC without a linked Pulse agent, which only ever gets that source,
lost memory pressure entirely: no triage flag, forecast or anomaly at 97%
of its limit, a "may include reclaimable cache" caveat in the seed, and
older memory alerts sent to model review every run with any resolve
verdict discarded.
The premise holds for QEMU but not for LXC. Proxmox's container mem is
cgroup usage with page cache already subtracted: PVE::CGroup's
get_memory_stat returns memory.current minus memory.stat file (cgroup v2)
or usage_in_bytes minus total_cache (v1), PVE::LXC::vmstatus reports it
as mem, and pvestatd feeds that value to the RRD that /cluster/resources
reads. A QEMU guest's listing mem is the host's view of guest RAM and
does count the guest's cache.
Qualification now takes the guest kind. A current, dated cluster-resources
reading establishes pressure for a Proxmox container and stays unknown for
QEMU; status-mem, status-freemem and derived-total-minus-used stay
cache-inclusive for both, and retained readings still cannot prove
pressure. The typed read state derives the kind from the resource type,
so Patrol, the observer and AI queries agree. The calculateLXCMemory
comment that called the listing value cache-inclusive is corrected.
Contract-Neutral: monitoring change is a corrected comment in calculateLXCMemory and its tests; LXC memory collection and sources are unchanged
PR 2804 removed three wall-clock windows from the Windows polling
contract. The sibling guest poll tests kept two of them, and on a
loaded pulse-dev they fail the same way. This is test-only.
1. A one second History window. Each fixture recorded its sample with
recordGuestMetrics(..., time.Now().Add(-time.Second)), taken after
the build. The builder stamps LastSeen before its tail, and the
fixtures then publish, snapshot or check alerts. guestObservedInCycle
skips a guest whose LastSeen precedes the cycle start, so a tail
over one second silently dropped the sample. The fixtures now take
the cycle start before collecting, as pollVMsAndContainersEfficient
does, in 17 call sites across 14 files. Two sites that assert no
point is written (unannotated deferral, unverified cluster disk)
could pass vacuously through the same window; they now cannot.
2. A one second client budget. The proxmox clients were built with
Timeout: time.Second against a loopback server. One late reply turns
into no-status or a deferred or fenced guest, and the History and
command counts the tests assert change. The fixtures now use a
shared 15 minute hang guard (17 clients across 15 files). None of
these fixtures relies on a timeout firing: their failure modes are
status codes, hijacked connections and malformed bodies.
3. monitor_pve_guest_cpu_authority_test.go waited five seconds for
startup maintenance and read stored points over the last minute.
It now waits on the maintenance barrier and reads the last hour,
as the shared History helper does since PR 2804.
Evidence on pulse-dev (load average 15-65, memory and I/O pressure
from other work), the 28 affected top-level tests, one process each:
- Plain, unmodified: TestGuestAgentAdmissionEvidenceContract failed
with reason=no-status. Plain, History fix alone:
TestGuestAgentOptionalReadOrderingContract failed the same way,
which is the client budget. Plain, this change, three runs: 84 of
84 pass.
- Control, a 1.2s stall after the builder stamps LastSeen (build
overlay on monitor_pve_guest_builders.go): unmodified, 17 tests
fail with History counts of zero; with the History fix, all 28
pass.
- Control, each proxmox client's first connection 1.1s late (build
overlay on pkg/tlsutil/fingerprint.go): unmodified, 17 tests fail
(no-status, healthy baseline absent); this change, 27 pass. The
other is below.
## What still can fail
A guest-agent fence lasts one minute (guestAgentUncertainCooldown).
TestGuestAgentOptionalReadOrderingContract checks that a cold collector
still sees it; one subtest stalled for about 85s under that load, the
fence expired first, and the check failed. The guard's clock is not
injectable from the test. Production deadlines the fixtures do not set
also remain: the 10s guest-agent call defaults (with every connection
1.1s late, one fixed test still hit agent-timeout) and the
transport's 10s dial and header limits.
Not changed: the 1s client budget in monitor_pve_guest_lxc_test.go
(paired with a 1s guest-agent FSInfo timeout and retries) and in
monitor_full_coverage_test.go (replication).
Contract-Neutral: test-only fixture timing; no runtime or contract change
Proxmox Mail Gateway 9 returns the cluster status cid as a string, so
decoding it into an int failed the whole cluster read and the poller
lost the node list (issue 2960). Pulse never reads cid, so the field is
no longer decoded and any format works.
With no nodes, the poller then requested backups from a node named
after the connection's display name ("PMG-01"), which PMG rejected with
a hostname-lookup error that pointed users at DNS. That fallback now
runs only when PMG answered with no cluster entries; after a failed
cluster read the request could never return backups, and the poll
already records the cluster failure.
Guest investigations could miss collected backup errors and could not read
storage history through canonical resource IDs. Share recovery point reads
with the HTTP API and monitoring history with charts, preserving tenant and
resource scope, timestamps, provenance, window bounds, and read failures.
Cover manifest projection, persisted recovery tasks, demo source parity,
retained storage history after restart, and API/tool evidence coherence.
Capture the cycle start before collecting the VM instead of inventing a
one-second window after collection. A slow recovery poll must remain part
of its original cycle when the fixture records its History sample.
The controlled-delay reproduction fails at the original history assertion
and passes with the real cycle start. Monitoring behavior is unchanged.
The full monitoring race suite at a1d8386e exposes four guest contracts whose optional metadata stubs return filesystem/network arrays for object-shaped OS and agent-info commands. The shared admission guard correctly pauses those contradictory replies. Return valid unknown metadata objects, bind the agent version fixture to /info, and reject unhandled fixture commands. Retain every original data, History, alert and recovery assertion; change no runtime guard, retry or collection policy.
Change-source: pulse-maintainer
Read only a uniquely matching node for agent filesystem admission and primary PVE task records for backup intent. Preserve exact identity, ambiguity refusal, detached ownership, task order and freshness rules; capture each replaceable state once. Add parity, concurrency, policy-boundary and allocation-scaling coverage, plus fixed-size benchmarks of both live entry points.
Contract-Neutral: Internal read projections only; collection, alert policy, emitted fields, persistence and frontend behavior are unchanged.
Change-source: pulse-maintainer
Clone only primary backup, replication and connection-health fields under State's lock. Preserve source-pointer capture, mock behaviour, normalization and the previous serialized projections; fleet metadata no longer drives the allocation cost of unrelated API reads.
Contract-Neutral: Scoped in-memory projections preserve backup/job/health values, empty and mock semantics, locking and existing clone ownership; no resource, API or collection contract changes.
Change-source: pulse-maintainer
A structurally valid reply for another guest command must not become an empty current inventory, acquire filesystem identity or release the serial-command fence. Check known command-exclusive fields and information-result shape before postflight lock checks; preserve null/empty/shared/unknown fields, partial row decoding, unusable file measurements, trust and independent live polling. Add six-reader cross-command controls, alias/expiry/recovery controls and actual builder/state/broadcast/History proof. This detects contradictory payload shapes, not native command correlation, thaw or report attribution.
Change-source: pulse-maintainer
Preserve contradictory rows before monitoring constructs its endpoint trust map. A final matching row must not mask earlier disagreement during saved-view consolidation. Cover both merge orders and retain the existing agreeing-format path; strengthen lifecycle configuration ownership checks.
Change-source: pulse-maintainer
Carry exact duplicate-row conflicts into owned client trust before map deduplication. Keep unresolved saved trust through initialization, missing-client retry and topology refresh without replacing pins or stopping trusted siblings. Cover actual monitor lifecycle routes and member projections alongside client TLS controls.
Change-source: pulse-maintainer
Resolve all saved pins for an endpoint before credential-bearing construction. Contradictory trust is an explicit failure, not a missing-pin fallback or first-use opportunity. Preserve independent authorities, agreeing formats and saved configuration; prove zero provider work, sibling monitoring and normal reload through the member projection.
Change-source: pulse-maintainer
Use scoped, detached producer tuples for canonical guests on failed nodes instead of publishing enrichment-only projections as readings. Keep original metric provenance, guest collection state and observation times, without cloning unrelated fleet data or changing guest command safety. The connected admission proof exposed and now covers this complete preservation path.
Change-source: pulse-maintainer
Require whole bounded, unambiguous enumerations on the efficient and node fallback routes. Preserve scoped empty inventories, LXC integer compatibility and ordinary counter/receipt semantics. Validate retained readings, History, breaches and template policy through actual fallback and recovery.
Change-source: pulse-maintainer
Consume the bounded response through EOF before admitting nodes or a cluster probe. Reject missing, ambiguous and incomplete inventories without leaking response details, retain scoped empty arrays and provider metadata, and cover trusted startup, recovery, cached reads and consuming endpoint projection.
Change-source: pulse-maintainer
Contract-Neutral: Tightens existing node-inventory and recovery-health admission without changing the public response schema, API surface, permissions, TLS or guest-command policy.
Require the actual nodes/login probe to succeed at startup, recovery and lazy selection instead of accepting guest-like response text. Retain failed single-endpoint health until an ordinary request succeeds, preserving cached last-resort reads, real guest error handling, temporary rate-limit handling and trust policy. Add producing-path and connected projection regressions and revise the old nodes-as-guest fixture contract.
Change-source: pulse-maintainer
The projection fixture now uses the actual saved ClusterEndpoint schema. Give each malformed-filesystem fixture an independent base path so reused listener ports cannot borrow a previous live uncertainty fence; all real guard state and response assertions remain.
Contract-Neutral: Test-only schema correction and independent synthetic endpoint identity; no production policy, deadline, wire or configuration changes.
Change-source: pulse-maintainer